MyBatis框架的延迟加载、MyBatis缓存、MyBatis注解开发。
MyBatis延迟加载策略
一、延迟加载的基本概念 1、延迟加载 延迟加载是指在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称为懒加载(按需加载)。
2、优点 先从单表查询,需要时再从关联表查询,大大提高了数据库性能,因为查询单表要比关联查询多张表速度要快。
3、缺点 因为只有当用到数据库时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。
4、立即加载 不管使用不使用,只要一调用方法,马上发起查询。
5、延迟加载和立即加载的使用时机 在一对多、多对多、多对一、一对一的四种表关系中可将其分为具体的两类进行分析:
一对多和多对多: 通常在这种情况下都是使用延迟加载的形式进行查询操作。
多对一和一对一: 通常在这种情况下都是使用立即加载的形式进行查询操作。
延迟加载指得其实是先查询一张表,然后根据从这张表里获取的数据再去另外一张表进行查询。以前的查询方式是先将两张关联表查询出来,然后通过相互关联的外键和主键再进行查询,这样十分浪费资源。而延迟查询却可以少查一张表,只查询表中的一部分数据。
二、使用assocation实现延迟加载 1、编写账户表和用户表的Dao接口 1 2 3 4 5 6 7 8 9 10 11 12 13 List<Account> findAll () ; User findById (int id) ;
2、编写账户表的持久层映射文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="com.itheima.dao.IAccountDao" > <resultMap id ="accountUserMap" type ="account" > <id property ="id" column ="id" > </id > <result column ="uid" property ="uid" > </result > <result column ="money" property ="money" > </result > <association property ="user" javaType ="user" select ="com.itheima.dao.IUserDao.findById" column ="uid" > </association > </resultMap > <select id ="findAll" resultMap ="accountUserMap" > select * from account </select > <select id ="findById" resultType ="com.itheima.domain.Account" parameterType ="int" > select * from account where uid = #{uid} </select > </mapper >
association标签:
select属性:内容为关联表的全限定dao接口名和方法名组。
colum属性:内容为传递给select方法的参数。
3、开启MyBatis延迟加载策略 在SqlMapConfig.xml中添加延迟加载配置
1 2 3 4 5 <settings > <setting name ="lazyLoadingEnabled" value ="true" /> <setting name ="aggressiveLazyLoading" value ="false" /> </settings >
4、编写测试类进行测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 `package com.itheima.test; import com.itheima.dao.IAccountDao;import com.itheima.domain.Account;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import org.junit.After;import org.junit.Before;import org.junit.Test;import java.io.InputStream;import java.util.List;public class IAccountDaoTest { private InputStream in = null ; private SqlSession session = null ; private IAccountDao accountDao; @Before public void init () throws Exception { in = Resources.getResourceAsStream("SqlMapConfig.xml" ); SqlSessionFactory factory = new SqlSessionFactoryBuilder ().build(in); session = factory.openSession(true ); accountDao = session.getMapper(IAccountDao.class); } @After public void destroy () throws Exception { session.close(); in.close(); } @Test public void findByAllTest () { List<Account> accounts = accountDao.findAll(); for (Account account: accounts) { System.out.println("---------------------------" ); System.out.println(account); System.out.println(account.getUser()); } } }
运行结果:
三、使用Collection实现延迟加载 1、配置编写User实体类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 package com.itheima.domain;import java.util.Date;import java.util.List;public class User { private Integer id; private String username; private Date birthday; private String sex; private String address; private List<Account> accounts; public User () { } public List<Account> getAccounts () { return accounts; } public void setAccounts (List<Account> accounts) { this .accounts = accounts; } public Integer getId () { return id; } public void setId (Integer id) { this .id = id; } public String getUsername () { return username; } public void setUsername (String username) { this .username = username; } public Date getBirthday () { return birthday; } public void setBirthday (Date birthday) { this .birthday = birthday; } public String getSex () { return sex; } public void setSex (String sex) { this .sex = sex; } public String getAddress () { return address; } public void setAddress (String address) { this .address = address; } @Override public String toString () { return "User{" + "id=" + id + ", username='" + username + '\'' + ", birthday=" + birthday + ", sex='" + sex + '\'' + ", address='" + address + '\'' + '}' ; } }
2、编写账户表和用户表的Dao接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 List<Account> findById (int uid) ; List<User> findByAll () ;
3、编写用户表的持久层映射文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="com.itheima.dao.IUserDao" > <resultMap id ="userMap" type ="user" > <id property ="id" column ="id" > </id > <result property ="username" column ="username" > </result > <result property ="address" column ="address" > </result > <result property ="sex" column ="sex" > </result > <result property ="birthday" column ="birthday" > </result > <collection property ="accounts" ofType ="account" select ="com.itheima.dao.IAccountDao.findById" column ="id" > </collection > </resultMap > <select id ="findByAll" resultMap ="userMap" > select * from user </select > <select id ="findById" resultType ="com.itheima.domain.User" parameterType ="int" > select * from user where id = #{id} </select > </mapper >
4、编写测试类进行测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 package com.itheima.test;import com.itheima.dao.IUserDao;import com.itheima.domain.User;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import org.junit.After;import org.junit.Before;import org.junit.Test;import java.io.InputStream;import java.util.List;public class IUserDaoTest { private InputStream in = null ; private SqlSession session = null ; private IUserDao userDao; @Before public void init () throws Exception { in = Resources.getResourceAsStream("SqlMapConfig.xml" ); SqlSessionFactory factory = new SqlSessionFactoryBuilder ().build(in); session = factory.openSession(true ); userDao = session.getMapper(IUserDao.class); } @After public void destroy () throws Exception { session.close(); in.close(); } @Test public void findAllTest () { List<User> users = userDao.findByAll(); for (User user: users) { System.out.println("----------------------" ); System.out.println(user); System.out.println(user.getAccounts()); } } @Test public void findByIdTest () { User user = userDao.findById(45 ); System.out.println(user); } }
运行结果:
执行的语句
MyBatis缓存
一、MyBatis的一级缓存 1、缓存的概念 缓存是指存在于内存中的临时数据
2、缓存的优点 减少和数据库的交互次数,提高执行效率。
3、缓存数据限制 (1)适用于缓存的数据
经常查询并且不经常改变的数据。
数据的正确与否对最终结果影响不大的数据。
(2)不适用于缓存的数据
4、一级缓存 一级缓存指的是MyBatis中SqlSession对象的缓存。
当我们执行查询之后,查询的结果会同时存入到SqlSession提供的一块区域。
该区域是一个Map。当我们再次查询同样的数据,MyBatis会先去SqlSession中查询是否有,有的话直接拿来使用。
值得注意的是当SqlSession对象消失时,NyBatis的一级缓存也就消失了。
5、一级缓存的证明 (1)编写User实体类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 package com.itheima.domain;import java.util.Date;import java.util.List;public class User { private Integer id; private String username; private Date birthday; private String sex; private String address; public User () { } @Override public String toString () { return "User{" + "id=" + id + ", username='" + username + '\'' + ", birthday=" + birthday + ", sex='" + sex + '\'' + ", address='" + address + '\'' + '}' ; } public Integer getId () { return id; } public void setId (Integer id) { this .id = id; } public String getUsername () { return username; } public void setUsername (String username) { this .username = username; } public Date getBirthday () { return birthday; } public void setBirthday (Date birthday) { this .birthday = birthday; } public String getSex () { return sex; } public void setSex (String sex) { this .sex = sex; } public String getAddress () { return address; } public void setAddress (String address) { this .address = address; } }
(2)编写持久层Dao接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package com.itheima.dao;import com.itheima.domain.User;import java.util.List;public interface IUserDao { List<User> findByAll () ; User findById (int id) ; }
(3)编写持久层Dao的映射文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="com.itheima.dao.IUserDao" > <select id ="findByAll" resultType ="user" > select * from user u left outer join account a on u.id = a.uid </select > <select id ="findById" resultType ="com.itheima.domain.User" parameterType ="int" > select * from user where id = #{id} </select > </mapper >
(4)编写测试类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 package com.itheima.test;import com.itheima.dao.IUserDao;import com.itheima.domain.User;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import org.junit.After;import org.junit.Before;import org.junit.Test;import java.io.InputStream;import java.util.List;public class IUserDaoTest { private InputStream in = null ; private SqlSession sqlSession = null ; private IUserDao userDao; private SqlSessionFactory factory; @Before public void init () throws Exception { in = Resources.getResourceAsStream("SqlMapConfig.xml" ); factory = new SqlSessionFactoryBuilder ().build(in); sqlSession = factory.openSession(true ); userDao = sqlSession.getMapper(IUserDao.class); } @After public void destroy () throws Exception { sqlSession.close(); in.close(); } @Test public void findByAll () { List<User> users = userDao.findByAll(); for (User user: users) { System.out.println("----------------------" ); System.out.println(user); } } @Test public void testFirstLevelCache () { User user1 = userDao.findById(41 ); User user2 = userDao.findById(41 ); System.out.println(user1 == user2); } }
运行结果
由上图可知只执行了一次Sql查询语句。而获取的两个User对象也是同一个对象。
(5)重新编写测试类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Test public void testFirstLevelCache () { User user1 = userDao.findById(41 ); sqlSession.clearCache(); userDao = sqlSession.getMapper(IUserDao.class); User user2 = userDao.findById(41 ); System.out.println("------------------------" ); System.out.println(user1 == user2); System.out.println("------------------------" ); }
此时的运行结果为
由上图可知两个对象不一致,并且查询了两次。证明了缓存的存在
6、一级缓存的同步 (1)在用户表的Dao接口中新添加一个方法 1 2 3 4 5 void updataUser (User user) ;
(2)编写Dao接口的映射文件 1 2 3 4 <update id ="updataUser" parameterType ="user" > update user set username = #{username} , address = #{address} where id = #{id} </update >
(3)再次修改之前的测试类 这一次此时缓存区的同步信息能力
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Test public void testClearlCache () { User user1 = userDao.findById(41 ); user1.setUsername("updata user clear cache" ); user1.setAddress("陕西汉中" ); userDao.updataUser(user1); User user2 = userDao.findById(41 ); System.out.println(user1 == user2); }
运行结果
由上面的结果得知这一次并没有从缓存区获取原来的对象,而是在修改完后重新查找了一次第41号对象的结果。
7、一级缓存的分析 一级缓存是SqlSession范围的缓存,当调用SqlSession的修改、添加、删除、commit()、close()方法时会清空一级缓存区。
当第一次发起查询用户id为41的用户信息时,先去缓存区中查找缓存区中是否存在id为41的用户信息,如果没有再从数据库中进行查询。
当得到用户信息,将用户信息存储到一级缓存中。
当SqlSession区执行commit操作(增删改),会清空SqlSession中的一级缓存,这样做的目的是为了让SqlSession中的数据始终是最新的信息,避免脏读。
当第二次发起查询id为41的用户信息时,先去缓存区中查找id为41的用户信息是否存在,若存在则直接从缓存区中获取用户信息。
二、二级缓存 1、二级缓存 二级缓存指的是MyBatis中SqlSessionFactroy对象的缓存。由同一个SqlSessionFactroy对象创建的SqlSession对象。
2、结构图
在开启MyBatis的二级缓存之后
SqlSession1去查询用户信息,将查询到的用户数据存储到二级缓存中。
此时若SqlSession3去执行相同mapper映射下sql,执行commit提交,将会清空该mapper映射下的二级缓存区域数据。
SqlSessiion2查询与SqlSession1相同的用户信息,首先会去缓存中找是否存在数据,如果存在直接从缓存中读取数据。
3、二级缓存的开启与关闭 (1)第一步:在SqlMapConfig.xml开启二级缓存 1 2 3 4 <settings > <setting name ="cacheEnabled" value ="true" /> </settings >
因为 cacheEnabled 的取值默认就为 true,所以这一步可以省略不配置。为 true 代表开启二级缓存;为false 代表不开启二级缓存。
(2)第二步:配置相关的Mapper映射文件 标签表示当前这个 mapper 映射将使用二级缓存,区分的标准就看 mapper 的 namespace 值。
1 2 3 4 5 6 7 8 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="com.itheima.dao.IUserDao" > <cache > </cache > </mapper >
(3)第三步:配置statement上面的useCache属性 1 2 3 4 <select id ="findById" resultType ="user" parameterType ="int" useCache ="true" > select * from user where id = #{uid} </select >
将 UserDao.xml 映射文件中的标签中设置 useCache=”true”代表当前这个 statement 要使用二级缓存,如果不使用二级缓存可以设置为 false。
注意:针对每次查询都需要最新的数据 sql,要设置成 useCache=false,禁用二级缓存。
4、二级缓存测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 package com.itheima.test;import com.itheima.dao.IUserDao;import com.itheima.domain.User;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import org.junit.After;import org.junit.Before;import org.junit.Test;import java.io.InputStream;import java.util.List;public class SecondLevelCacheTest { private InputStream in = null ; private SqlSessionFactory factory; @Before public void init () throws Exception { in = Resources.getResourceAsStream("SqlMapConfig.xml" ); factory = new SqlSessionFactoryBuilder ().build(in); } @After public void destroy () throws Exception { in.close(); } @Test public void testFirstLevelCache () { SqlSession sqlSession1 = factory.openSession(); IUserDao userDao1 = sqlSession1.getMapper(IUserDao.class); User user1 = userDao1.findById(41 ); sqlSession1.close(); SqlSession sqlSession2 = factory.openSession(); IUserDao userDao2 = sqlSession2.getMapper(IUserDao.class); User user2 = userDao2.findById(41 ); sqlSession2.close(); System.out.println("------------------------" ); System.out.println(user1 == user2); System.out.println("------------------------" ); } }
运行结果
由上面的图可知只执行了一次,第二次执行是从缓存区中读取的。
这里的false是因为存入SqlSessionFactroy区的是数据而不是对象,所以是两个对象。
5、二级缓存的注意事项 在使用二级缓存时,所缓存的类必须要实现 java.io.Serializable 接口这种就可以使用序列化方式来保存对象。
MyBatis注解开发
一、MyBatis注解开发的环境搭建 1、常用注解说明
注解
注解说明
@Insert
实现新增
@Updata
实现更新
@Delete
实现删除
@Select
实现查询
@Result
实现结果集封装
@Results
可以与@Result一起使用,封装多个结果集
@ResultMap
实现引用@Results定义的封装
@One
实现一对一结果集封装
@Many
实现一对多结果集封装
@SelectProvider
实现动态SQL映射
@CacheNamespace
实现注解二级缓存的使用
2、配置POM.xml文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 <?xml version="1.0" encoding="UTF-8" ?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <groupId > eesy_zhujiekaifa</groupId > <artifactId > eesy_zhujiekaifa</artifactId > <version > 1.0-SNAPSHOT</version > <packaging > jar</packaging > <dependencies > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.4.5</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 5.1.6</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.10</version > </dependency > <dependency > <groupId > log4j</groupId > <artifactId > log4j</artifactId > <version > 1.2.12</version > </dependency > </dependencies > </project >
3、导入数据库信息文件——jdbcConfig.properties 1 2 3 4 jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/eesy_mybatis jdbc.username=root jdbc.password=root
4、导入配置文件解析文件——log4j.properties
5、配置SqlMapConfig.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration > <properties resource ="jdbcConfig.properties" /> <typeAliases > <package name ="com.itheima.domain" /> </typeAliases > <environments default ="mysql" > <environment id ="mysql" > <transactionManager type ="JDBC" > </transactionManager > <dataSource type ="POOLED" > <property name ="driver" value ="${jdbc.driver}" /> <property name ="url" value ="${jdbc.url}" /> <property name ="username" value ="${jdbc.username}" /> <property name ="password" value ="${jdbc.password}" /> </dataSource > </environment > </environments > <mappers > <package name ="com.itheima.dao" /> </mappers > </configuration >
这样注解开放的环境就配置好了,其实和非注解开发的环境搭建是一样的。
二、单表的CRUD操作 1、配置实体类对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 package com.itheima.domain;import java.io.Serializable;import java.util.Date;public class User implements Serializable { private Integer id; private String username; private String sex; private String address; private Date birthday; public User () { } public User (Integer id, String username, String sex, String address, Date birthday) { this .id = id; this .username = username; this .sex = sex; this .address = address; this .birthday = birthday; } public Integer getId () { return id; } public void setId (Integer id) { this .id = id; } public String getUsername () { return username; } public void setUsername (String username) { this .username = username; } public String getSex () { return sex; } public void setSex (String sex) { this .sex = sex; } public String getAddress () { return address; } public void setAddress (String address) { this .address = address; } public Date getBirthday () { return birthday; } public void setBirthday (Date birthday) { this .birthday = birthday; } @Override public String toString () { return "User{" + "id=" + id + ", username='" + username + '\'' + ", sex='" + sex + '\'' + ", address='" + address + '\'' + ", birthday=" + birthday + '}' ; } }
值得注意的是实体类需要实现序列化接口(Serializable)
2、编写实体类的Dao接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 package com.itheima.dao;import com.itheima.domain.User;import org.apache.ibatis.annotations.Delete;import org.apache.ibatis.annotations.Insert;import org.apache.ibatis.annotations.Select;import org.apache.ibatis.annotations.Update;import java.util.List;public interface IUserDao { @Select("select * from user") List<User> findAll () ; @Update("update user set username = #{username},sex = #{sex},address = #{address},birthday = #{birthday} where id = #{id}") int updataUser (User user) ; @Insert("insert into user(username,sex,address,birthday) values(#{username},#{sex},#{address},#{birthday})") int insertUser (User user) ; @Delete("delete from user where id = #{id}") int deleteUser (int id) ; @Select("select * from user where id = #{id}") User findById (Integer id) ; @Select("select * from user where username like '%${value}%'") List<User> findByName (String username) ; @Select("select count(*) from user") Integer findTotal () ; }
3、编写测试类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 package com.itheima.test;import com.itheima.dao.IUserDao;import com.itheima.domain.User;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import org.junit.After;import org.junit.Before;import org.junit.Test;import java.io.InputStream;import java.util.Date;import java.util.List;public class AnnoCRUDTest { private InputStream in; private SqlSessionFactory factory; private SqlSession sqlSession; private IUserDao userDao; @Before public void init () throws Exception{ in = Resources.getResourceAsStream("SqlMapConfig.xml" ); factory = new SqlSessionFactoryBuilder ().build(in); sqlSession = factory.openSession(true ); userDao = sqlSession.getMapper(IUserDao.class); } @After public void destroy () throws Exception{ sqlSession.close(); in.close(); } @Test public void findAllTest () { List<User> users = userDao.findAll(); for (User user : users) { System.out.println(user); } } @Test public void insertUserTest () { System.out.println(userDao.insertUser(new User (null ,"mybatis insert" ,"男" ,"西安" ,new Date ()))); } @Test public void updataUserTest () { System.out.println(userDao.updataUser(new User (54 ,"mybatis updata" ,"女" ,"成都" ,new Date ()))); } @Test public void findByIdTest () { System.out.println(userDao.findById(54 )); } @Test public void findByNameTest () { List<User> users = userDao.findByName("王" ); for (User user: users) { System.out.println(user); } } @Test public void findTotalTest () { System.out.println(userDao.findTotal()); } @Test public void deletdUserTest () { System.out.println(userDao.deleteUser(54 )); } }
三、建立实体类属性和数据库表列的对应关系 1、修改实体类表的属性 1 2 3 4 5 private Integer userId; private String username; private String userSex; private String userAddress; private Date userBirthday;
数据库列的名称
2、重新编写Dao接口内容 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 package com.itheima.dao;import com.itheima.domain.User;import org.apache.ibatis.annotations.Result;import org.apache.ibatis.annotations.ResultMap;import org.apache.ibatis.annotations.Results;import org.apache.ibatis.annotations.Select;import java.util.List;public interface IUserDao { @Select("select * from user") @Results(id = "userMap",value = { @Result(id = true,column = "id",property = "userId"), @Result(column = "username",property = "username"), @Result(column = "sex",property = "userSex"), @Result(column = "address",property = "userAddress"), @Result(column = "birthday",property = "userBirthday"), }) List<User> findAll () ; @Select("select * from user where id = #{id}") @ResultMap(value = {"userMap"}) User findById (Integer id) ; @Select("select * from user where username like #{username}") @ResultMap("userMap") List<User> findByName (String username) ; }
@Results注解
id属性和非注解时的resultMap一样,是该对应关系的唯一标识。
value属性用于配置实体类和数据库表列的对应关系。
@ResultMap注解 :用于调用配置好的对应关系。
3、编写测试类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 package com.itheima.test;import com.itheima.dao.IUserDao;import com.itheima.domain.User;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import org.junit.After;import org.junit.Before;import org.junit.Test;import java.io.InputStream;import java.util.List;public class AnnotationCRUDTest { private InputStream in; private SqlSessionFactory factory; private SqlSession sqlSession; private IUserDao userDao; @Before public void init () throws Exception{ in = Resources.getResourceAsStream("SqlMapConfig.xml" ); factory = new SqlSessionFactoryBuilder ().build(in); sqlSession = factory.openSession(true ); userDao = sqlSession.getMapper(IUserDao.class); } @After public void destory () throws Exception{ sqlSession.close(); in.close(); } @Test public void findAllTest () { List<User> users = userDao.findAll(); for (User user : users) { System.out.println(user); } } @Test public void findByIdTest () { System.out.println(userDao.findById(42 )); } @Test public void findByNameTest () { List<User> users = userDao.findByName("%王%" ); for (User user: users) { System.out.println(user); } } }
四、一对一注解查询配置 1、新添加一个Account实体类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 package com.itheima.domain;import java.io.Serializable;public class Account implements Serializable { private Integer id; private Integer uid; private Double money; private User user; public User getUser () { return user; } public void setUser (User user) { this .user = user; } public Integer getId () { return id; } public void setId (Integer id) { this .id = id; } public Integer getUid () { return uid; } public void setUid (Integer uid) { this .uid = uid; } public Double getMoney () { return money; } public void setMoney (Double money) { this .money = money; } @Override public String toString () { return "Account{" + "id=" + id + ", uid=" + uid + ", money=" + money + '}' ; } }
2、配置Account实体类的Dao接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package com.itheima.dao;import com.itheima.domain.Account;import org.apache.ibatis.annotations.One;import org.apache.ibatis.annotations.Result;import org.apache.ibatis.annotations.Results;import org.apache.ibatis.annotations.Select;import org.apache.ibatis.mapping.FetchType;import java.util.List;public interface IAccountDao { @Select("select * from account") @Results(id = "accountMap",value = { @Result(id = true,column = "id" ,property = "id"), @Result(column = "uid",property = "uid"), @Result(column = "money",property = "money"), @Result(property = "user",column = "uid",one = @One( select = "com.itheima.dao.IUserDao.findById",fetchType = FetchType.EAGER)) }) List<Account> findAll () ; @Select("select * from account where uid = #{uid}") Account findByUid (Integer uid) ; }
此时使用的依然是**@Result注解**,select属性是关联表的实体类的dao接口的方法,fetchType属性是延迟与立即加载的设置。
3、编写测试类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 package com.itheima.test;import com.itheima.dao.IAccountDao;import com.itheima.domain.Account;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import org.junit.After;import org.junit.Before;import org.junit.Test;import java.io.InputStream;import java.util.List;public class AccountTest { private InputStream in; private SqlSessionFactory factory; private SqlSession sqlSession; private IAccountDao accountDao; @Before public void init () throws Exception{ in = Resources.getResourceAsStream("SqlMapConfig.xml" ); factory = new SqlSessionFactoryBuilder ().build(in); sqlSession = factory.openSession(); accountDao = sqlSession.getMapper(IAccountDao.class); } @After public void destory () throws Exception{ sqlSession.commit(); sqlSession.close(); in.close(); } @Test public void findAll () { List<Account> accounts = accountDao.findAll(); for (Account account: accounts) { System.out.println("------------------------------" ); System.out.println(account); System.out.println(account.getUser()); } } }
五、一对多注解查询配置 1、修改User实体类 像原先的User实体类中添加一个Account实体类的List集合
1 2 3 4 5 6 7 8 9 10 private List<Account> accounts; public List<Account> getAccounts () { return accounts; } public void setAccounts (List<Account> accounts) { this .accounts = accounts; }
2、修改User实体类的Dao接口注解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Select("select * from user") @Results(id = "userMap",value = { @Result(id = true,column = "id",property = "userId"), @Result(column = "username",property = "username"), @Result(column = "sex",property = "userSex"), @Result(column = "address",property = "userAddress"), @Result(column = "birthday",property = "userBirthday"), @Result(property = "accounts",column = "id",many = @Many(select = "com.itheima.dao.IAccountDao.findByUid",fetchType = FetchType.LAZY)) }) List<User> findAll () ;
3、编写测试方法 1 2 3 4 5 6 7 8 9 10 11 12 @Test public void findAllTest () { List<User> users = userDao.findAll(); for (User user : users) { System.out.println("--------------------------" ); System.out.println(user); System.out.println(user.getAccounts()); } }
总结:一对多和一对一的配置方式相同。
六、注解开发的二级缓存 1、开启方法 (1)在SqlMapConfig.xml添加配置文件 1 2 3 4 <settings > <setting name ="cacheEnabled" value ="true" /> </settings >
但是这个配置可以不添加,因为在MyBatis的官方文档中默认值是”true“,即默认开启。
(2)在需要开启二级缓存的Dao接口上添加注解 1 2 @CacheNamespace(blocking = true)
如此二级缓存就开启完成了。
参考资料
传智黑马MyBatis
[https://www.bilibili.com/video/BV1SJ411679L] :