MyBatis-04
一、Mybatis的延迟加载
在多表关联查询时,比如查询用户信息,及其关联的帐号信息,在查询用户时就直接把帐号信息也一并查询出来了。但是在实际开发中,并不是每次都需要立即使用帐号信息,这时候,就可以使用延迟加载策略了。
1. 什么是延迟加载
1.1 立即加载的概念
不管数据是否需要使用,只要调用了方法,就立即发起查询。比如:上节课的多表关联查询,查询帐号,得到关联的用户。
1.2 延迟加载的概念
延迟加载,也叫按需加载,或者叫懒加载。只有当真正使用到数据的时候,才发起查询。不使用不发起查询。比如:查询用户信息,不使用accounts的时候,不查询帐号的数据;只有当使用了用户的accounts,Mybatis再发起查询帐号的信息
- 好处:先从单表查询,需要使用关联数据时,才进行关联数据的查询。 单表查询的速度要比多表关联查询速度快
- 坏处:当需要使用数据时才会执行SQL。这样大批量的SQL执行的情况下,会造成查询等待时间比较长
1.3 延迟加载的使用场景
- 一对一(多对一),通常不使用延迟加载(建议)。比如:查询帐号,关联加载用户信息
- 一对多(多对多),通常使用延迟加载(建议)。比如:查询用户,关联加载帐号信息
1.4 ★★★★懒加载实现的过程★★★★
只有多表关联查询时,才需要懒加载。
- 一对一的懒加载
- 修改JavaBean-Account,需要有另外一个JavaBean(User)的引用
- 准备好关联查询使用的方法:根据id查询User对象----findUserByUid
- 在映射器接口里编写查询的代码:查询帐号信息的功能
- 在映射配置文件里,封装结果使用resultMap和association标签。
- association:需要增加两个属性
- select:调用已经准备好的方法,懒加载关联查询
- column:调用准备好的方法时,需要的参数从哪个字段里取
- association:需要增加两个属性
- 修改Mybatis的核心配置文件,开启延迟加载
- 一对多的懒加载
- 修改JavaBean-User,需要有另外一个JavaBean(Account)的集合
- 准备好关联查询使用的方法:根据uid查询得到Account的集合—findAccountsByUid
- 在映射器接口里编写查询用户的代码:
- 在映射配置文件里,封装结果使用resultMap和collection标签。
- collection:需要增加两个属性
- select:调用已经准备好的方法,懒加载关联查询。com.viking.dao.IAccountDao.findAccountsByUid
- column:调用准备好的方法时,需要的参数从哪个字段里取
- collection:需要增加两个属性
- 修改Mybatis的核心配置文件,开启延迟加载
2. 实现一对一(多对一)的延迟加载
需求:查询帐号信息,及其关联的用户信息。使用懒加载的方式实现。
2.1 一对一延迟加载的要点
- 要有映射器IUserDao,提供findUserById的方法,供懒加载时使用
- 要有映射器IAccountDao查询帐号信息,使用association实现懒加载关联的用户信息
- 在核心配置文件中,开启懒加载
2.2 准备关联加载的方法备用(IUserDao.findUserById)
-
创建Maven的Java项目,设置坐标,配置好Mybatis的依赖
-
创建JavaBean:User和Account
注意:Account中要有User的引用
public class User { private Integer id; private String username; private Date birthday; private String sex; private String 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; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", birthday=" + birthday + ", sex='" + sex + '\'' + ", address='" + address + '\'' + '}'; } }
public class Account { private Integer id; private Integer uid; private Double money; private 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; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } @Override public String toString() { return "Account{" + "id=" + id + ", uid=" + uid + ", money=" + money + ", user=" + user + '}'; } }
-
创建映射器接口IUserDao,提供findUserById方法(准备好备用)
public interface IUserDao { User findUserById(Integer uid); }
-
创建映射配置文件IUserDao.xml(准备好备用)
<?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.viking.dao.IUserDao"> <select id="findUserById" parameterType="int" resultType="user"> select * from user where id = #{uid} </select> </mapper>
-
创建Mybatis的核心配置文件,配置好别名和映射器
<?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> <typeAliases> <package name="com.viking.bean"/> </typeAliases> <environments default="mysql_mybatis"> <environment id="mysql_mybatis"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql:///mybatis"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <mappers> <package name="com.viking.dao"/> </mappers> </configuration>
2.3 查询帐号信息,调用准备好的关联加载的方法,实现懒加载
-
创建映射器接口IAccountDao
public interface IAccountDao { /** * 查询一个帐号信息,懒加载关联的用户信息 */ Account findById(Integer id); }
-
创建映射配置文件IAccountDao.xml,配置映射信息
<?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.viking.dao.IAccountDao"> <select id="findById" parameterType="int" resultMap="accountLazyUser"> select * from account where id = #{id} </select> <resultMap id="accountLazyUser" type="account"> <id property="id" column="id"/> <result property="uid" column="uid"/> <result property="money" column="money"/> <!-- association标签:用于封装关联的JavaBean对象 select:调用哪个statement,懒加载 得到关联的JavaBean对象 column:调用statement时,需要传递的参数值,从哪个字段中取出 --> <association property="user" javaType="user" column="uid" select="com.viking.dao.IUserDao.findUserById"/> </resultMap> </mapper>
-
修改Mybatis的核心配置文件,启动延迟加载
<!-- 把settings标签放到typeAliases之前 --> <settings> <!-- 启动延迟加载 --> <setting name="lazyLoadingEnabled" value="true"/> <!-- 禁用积极加载:使用按需加载 --> <setting name="aggressiveLazyLoading" value="false"/> </settings>
-
编写测试代码
public class MybatisLazyTest { private InputStream is; private SqlSession session; private IAccountDao accountDao; /** * 测试 一对一的延迟加载效果 */ @Test public void testFindAccountById(){ Account account = accountDao.findById(1); System.out.println(account.getId()+", " +account.getMoney()); //如果不执行下面这行代码,Mybatis是不会发起查询用户信息的SQL语句的。 System.out.println(account.getUser()); } @Before public void init() throws IOException { is = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(is); session = factory.openSession(); accountDao = session.getMapper(IAccountDao.class); } @After public void destory() throws IOException { session.close(); is.close(); } }
3. 实现一对多(多对多)的延迟加载
需求:查询用户信息,及其关联的帐号信息集合。使用延迟加载实现。
3.1 一对多延迟加载的要点
- 要有映射器IAccountDao,提供findAccountsByUid的方法,供懒加载时使用
- 要有映射器IUserDao,查询用户信息,使用collection实现懒加载帐号关联的帐号信息
- 在核心配置文件中,开启懒加载
3.2 准备关联加载的方法备用(IAccountDao.findAccountsByUid)
-
创建Maven的Java项目,配置好坐标,引入Mybatis的依赖
-
创建JavaBean:User和Account
注意:User中要有Account的集合
public class Account { private Integer id; private Integer uid; private Double money; 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 + '}'; } }
public class User { private Integer id; private String username; private Date birthday; private String sex; private String address; private List<Account> 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; } public List<Account> getAccounts() { return accounts; } public void setAccounts(List<Account> accounts) { this.accounts = accounts; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", birthday=" + birthday + ", sex='" + sex + '\'' + ", address='" + address + '\'' + ", accounts=" + accounts + '}'; } }
-
创建映射器接口IAccountDao,提供findAccountsByUid方法(准备好备用)
public interface IAccountDao { List<Account> findAccountsByUid(Integer uid); }
-
创建映射配置文件IAccountDao.xml,配置映射信息
<?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.viking.dao.IAccountDao"> <select id="findAccountsByUid" resultType="account"> select * from account where uid = #{uid} </select> </mapper>
-
准备Mybatis的核心配置文件,配置好别名和映射器
<?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> <typeAliases> <package name="com.viking.bean"/> </typeAliases> <environments default="mysql_mybatis"> <environment id="mysql_mybatis"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql:///mybatis"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <mappers> <package name="com.viking.dao"/> </mappers> </configuration>
3.3 查询用户信息,调用准备好的关联加载的方法,实现懒加载
-
创建映射器接口IUserDao
public interface IUserDao { /** * 查询一个用户信息,懒加载关联的帐号信息集合 * @return */ User findUserById(Integer uid); }
-
创建映射配置文件IUserDao.xml
<?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.viking.dao.IUserDao"> <select id="findUserById" parameterType="int" resultMap="userLazyAccounts"> select * from user where id = #{uid} </select> <resultMap id="userLazyAccounts" type="user"> <id property="id" column="id"/> <result property="username" column="username"/> <result property="birthday" column="birthday"/> <result property="sex" column="sex"/> <result property="address" column="address"/> <collection property="accounts" ofType="account" column="id" select="com.viking.dao.IAccountDao.findAccountsByUid"/> </resultMap> </mapper>
-
修改Mybatis核心配置文件,开启延迟加载
<!-- 把settings标签放到typeAliases之前 --> <settings> <!-- 启动延迟加载 --> <setting name="lazyLoadingEnabled" value="true"/> <!-- 禁用积极加载:使用按需加载 --> <setting name="aggressiveLazyLoading" value="false"/> </settings>
-
编写测试代码
public class MybatisLazyTest { private InputStream is; private SqlSession session; private IUserDao userDao; /** * 测试 一对多的延迟加载效果 */ @Test public void testFindUserById(){ User user = userDao.findUserById(41); System.out.println(user.getUsername() + ", " + user.getAddress()); //如果不执行下面这行代码,Mybatis是不会发起查询帐号信息的SQL语句的 System.out.println(user.getAccounts()); } @Before public void init() throws IOException { is = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(is); session = factory.openSession(); userDao = session.getMapper(IUserDao.class); } @After public void destory() throws IOException { session.close(); is.close(); } }
二、Mybatis的缓存
Mybatis为了提高数据查询的效率,也提供了缓存的功能:一级缓存和二级缓存。
- 一级缓存:是SqlSession对象提供的缓存
- 二级缓存:是SqlSessionFactory对象的缓存,同一个SqlSessionFactory创建的多个SqlSession共享缓存
我们以查询一个用户信息为例,来演示Mybatis缓存的效果。
1. 准备Mybatis环境
-
创建Maven的Java项目,配置好坐标,引入Mybatis的依赖
-
创建JavaBean:User
注意:不要重写toString()方法,我们需要打印User对象的地址
public class User { private Integer id; private String username; private Date birthday; private String sex; private String 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; } }
-
创建映射器接口IUserDao
public interface IUserDao { User findUserById(Integer uid); }
-
创建映射配置文件IUserDao.xml
<?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.viking.dao.IUserDao"> <select id="findUserById" parameterType="int" resultType="user"> select * from user where id = #{uid} </select> </mapper>
-
准备Mybatis的核心配置文件,配置好别名和映射器
<?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> <typeAliases> <package name="com.viking.bean"/> </typeAliases> <environments default="mysql_mybatis"> <environment id="mysql_mybatis"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql:///mybatis"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <mappers> <package name="com.viking.dao"/> </mappers> </configuration>
-
准备好单元测试类备用
/** * Mybatis一级缓存效果演示 */ public class MybatisLevel1CacheTest { private InputStream is; private SqlSession session; private IUserDao dao; @Before public void init() throws IOException { is = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(is); session = factory.openSession(); dao = session.getMapper(IUserDao.class); } @After public void destory() throws IOException { session.close(); is.close(); } }
2. 一级缓存
2.1 什么是一级缓存
一级缓存,是SqlSession对象提供的缓存(无论用不用,始终都有的)。
当我们执行一次查询之后,查询的结果会同时缓存到SqlSession提供的一块存储区域中(是一个Map)。当我们再次查询同样的数据,Mybatis会优先从缓存中查找;如果找到了,就不再查询数据库。
2.2 一级缓存的清除
当调用了SqlSession对象的修改、添加、删除、commit()、close()、clearCache()等方法时,一级缓存会被清空。
2.3 一级缓存效果演示
/**
* 测试 Mybatis的一级缓存:
* SQL语句执行了一次、输出user1和user2的地址是相同的
* 说明Mybatis使用了缓存
*/
@Test
public void testLevel1Cache(){
User user1 = dao.findUserById(41);
System.out.println(user1);
User user2 = dao.findUserById(41);
System.out.println(user2);
}
/**
* 测试 清除Mybatis的一级缓存
* 两次打印的User地址不同,执行了两次SQL语句
* SqlSession的修改、添加、删除、commit()、clearCache()、close()都会清除一级缓存
*/
@Test
public void testClearLevel1Cache(){
User user1 = dao.findUserById(41);
System.out.println(user1);
session.clearCache();
User user2 = dao.findUserById(41);
System.out.println(user2);
}
3. 二级缓存
3.1 什么是二级缓存
指Mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象生产的SqlSession对象共享其缓存。二级缓存需要手动开启
3.2 开启二级缓存,及效果演示
-
修改Mybatis核心配置文件,开启全局的二级缓存开关
<!-- 把设置项添加到核心配置文件内,typeAliases之前 --> <settings> <!-- 增加此配置项,启动二级缓存(默认值就是true,所以这一步可以省略不配置) --> <setting name="cacheEnabled" value="true"/> </settings>
-
修改映射配置文件IUserDao.xml,让映射器支持二级缓存
<mapper namespace="com.viking.dao.IUserDao"> <!-- 把cache标签加到映射配置文件 mapper标签里 --> <cache/> ...... </mapper>
-
修改映射配置文件IUserDao中的findById,让此方法(statement)支持二级缓存
<!-- 如果statement的标签上,设置有的useCache="true",表示此方法要使用二级缓存 --> <select id="findById" parameterType="int" resultType="user" useCache="true"> select * from user where id = #{id} </select>
-
修改JavaBean:User
注意:如果要使用二级缓存,那么JavaBean需要实现Serializable接口
public class User implements Serializable { private Integer id; private String username; private Date birthday; private String sex; private String 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; } }
-
编写测试代码
/** * Mybatis二级缓存效果演示 */ public class MybatisLevel2CacheTest { private InputStream is; private SqlSessionFactory factory; /** * 测试二级缓存。 * 测试结果: * 虽然输出的user1和user2地址不同,但是SQL语句只执行了一次。 * Mybatis的二级缓存,保存的不是JavaBean对象,而是散列的数据。 * 当要获取缓存时,把这些数据重新组装成一个JavaBean对象,所以地址不同 */ @Test public void testLevel2Cache(){ SqlSession session1 = factory.openSession(); IUserDao dao1 = session1.getMapper(IUserDao.class); User user1 = dao1.findUserById(41); System.out.println(user1); session1.close(); SqlSession session2 = factory.openSession(); IUserDao dao2 = session2.getMapper(IUserDao.class); User user2 = dao2.findUserById(41); System.out.println(user2); session2.close(); } @Before public void init() throws IOException { is = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); factory = builder.build(is); } @After public void destory() throws IOException { is.close(); } }
三、Mybatis的注解开发
Mybatis也支持注解开发。但是需要明确的是,Mybatis仅仅是把映射配置文件 使用注解代替了;而Mybatis的核心配置文件,仍然是xml配置。
1. 常用注解介绍
- @Select:相当于映射配置文件里的select标签
- @Insert:相当于映射配置文件里的insert标签
- @SelectKey:相当于映射配置文件里的selectKey标签,用于添加数据后获取最新的主键值
- @Update:相当于映射配置文件里的update标签
- @Delete:相当于映射配置文件里的delete标签
- @Results:相当于映射配置文件里的resultMap标签
- @Result:相当于映射配置文件里的result标签,和@Results配合使用,封装结果集的
- @One:相当于映射配置文件里的association,用于封装关联的一个JavaBean对象
- @Many:相当于映射配置文件里的collection标签,用于封装关联的一个JavaBean对象集合
2. 使用注解实现简单CURD操作
2.1 准备Mybatis环境
-
创建Maven的Java项目,配置好坐标,并引入Mybatis的依赖
-
创建JavaBean:User
public class User { private Integer id; private String username; private Date birthday; private String sex; private String 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; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", birthday=" + birthday + ", sex='" + sex + '\'' + ", address='" + address + '\'' + '}'; } }
-
创建映射器接口IUserDao,备用
public interface IUserDao { }
-
准备Mybatis的核心配置文件,配置好别名和映射器
<?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> <typeAliases> <package name="com.viking.bean"/> </typeAliases> <environments default="mysql_mybatis"> <environment id="mysql_mybatis"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql:///mybatis"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <mappers> <package name="com.viking.dao"/> </mappers> </configuration>
-
准备好单元测试类备用
/** * Mybatis的注解开发功能测试--简单的CURD操作 */ public class MybatisAnnotationTest { private InputStream is; private SqlSession session; private IUserDao dao; @Before public void init() throws IOException { is = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); session = factory.openSession(); dao = session.getMapper(IUserDao.class); } @After public void destory() throws IOException { session.close(); is.close(); } }
2.2 查询全部用户
-
在映射器接口IUserDao中增加方法
@Select("select * from user") List<User> queryAll();
-
在测试类MybatisAnnotationTest中编写测试代码
@Test public void testQueryAll(){ List<User> users = dao.queryAll(); for (User user : users) { System.out.println(user); } }
2.3 根据主键查询一个用户
-
在映射器接口IUserDao中增加方法
@Select("select * from user where id = #{id}") User findById(Integer id);
-
在测试类MybatisAnnotationTest中编写测试代码
@Test public void testFindById(){ User user = dao.findById(41); System.out.println(user); }
2.4 添加用户
-
在映射器接口IUserDao中增加方法
@Insert("insert into user (id,username,birthday,sex,address) values (#{id},#{username},#{birthday},#{sex},#{address})") @SelectKey( statement = "select last_insert_id()", //查询最新主键值的SQL语句 resultType = Integer.class, //得到最新主键值的类型 keyProperty = "id", //得到最新主键值,保存到哪个属性里 before = false //是否在insert操作之前查询最新主键值 ) void save(User user);
-
在测试类MybatisAnnotationTest中编写测试代码
@Test public void testSave(){ User user = new User(); user.setUsername("小红"); user.setSex("女"); user.setAddress("中国钓鱼岛"); user.setBirthday(new Date()); System.out.println("保存之前:" + user); dao.save(user); session.commit(); System.out.println("保存之后:" + user); }
2.5 修改用户
-
在映射器接口IUserDao中增加方法
@Update("update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}") void edit(User user);
-
在测试类MybatisAnnotationTest中编写测试代码
@Test public void testEdit(){ User user = dao.findById(57); user.setAddress("广州"); dao.edit(user); session.commit(); }
2.6 删除用户
-
在映射器接口IUserDao中增加方法
@Delete("delete from user where id = #{id}") void delete(Integer id);
-
在测试类MybatisAnnotationTest中编写测试代码
@Test public void testDelete(){ dao.delete(57); session.commit(); }
2.7 JavaBean属性名和字段名不一致的情况处理
-
创建JavaBean: User2
public class User2 { private Integer userId; private String username; private Date userBirthday; private String userSex; private String userAddress; public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Date getUserBirthday() { return userBirthday; } public void setUserBirthday(Date userBirthday) { this.userBirthday = userBirthday; } public String getUserSex() { return userSex; } public void setUserSex(String userSex) { this.userSex = userSex; } public String getUserAddress() { return userAddress; } public void setUserAddress(String userAddress) { this.userAddress = userAddress; } @Override public String toString() { return "User2{" + "userId=" + userId + ", username='" + username + '\'' + ", userBirthday=" + userBirthday + ", userSex='" + userSex + '\'' + ", userAddress='" + userAddress + '\'' + '}'; } }
-
在映射器接口IUserDao中增加方法
@Select("select * from user") @Results({ @Result(property = "userId", column = "id", id = true), @Result(property = "username", column = "username"), @Result(property = "userBirthday", column = "birthday"), @Result(property = "userSex", column = "sex"), @Result(property = "userAddress", column = "address") }) List<User2> queryAllUser2();
-
在测试类MybatisAnnotationTest中编写测试代码
@Test public void testQueryAllUser2(){ List<User2> user2List = dao.queryAllUser2(); for (User2 user2 : user2List) { System.out.println(user2); } }
3. 使用注解实现复杂关系操作-多表关联查询
3.1 准备Mybatis环境
-
创建Maven的Java项目,设置好坐标,引入Mybatis的依赖
-
创建JavaBean
注意:Account中要有User的引用,User中要有Account的集合
public class User { private Integer id; private String username; private Date birthday; private String sex; private String address; private List<Account> 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; } public List<Account> getAccounts() { return accounts; } public void setAccounts(List<Account> accounts) { this.accounts = accounts; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", birthday=" + birthday + ", sex='" + sex + '\'' + ", address='" + address + '\'' + ", accounts=" + accounts + '}'; } }
public class Account { private Integer id; private Integer uid; private Double money; private 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; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } @Override public String toString() { return "Account{" + "id=" + id + ", uid=" + uid + ", money=" + money + ", user=" + user + '}'; } }
-
创建映射器接口IUserDao和IAccountDao,备用
public interface IAccountDao { }
public interface IUserDao { }
-
准备好核心配置文件,配置好别名和映射器
<?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> <typeAliases> <package name="com.viking.bean"/> </typeAliases> <environments default="mysql_mybatis"> <environment id="mysql_mybatis"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql:///mybatis"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <mappers> <package name="com.viking.dao"/> </mappers> </configuration>
-
准备好单元测试类备用
/** * Mybatis的注解开发--复杂的注解开发,多表关联查询测试类 */ public class MybatisComplexAnnotationTest { private InputStream is; private SqlSession session; private IUserDao userDao; private IAccountDao accountDao; @Before public void init() throws IOException { is = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); session = factory.openSession(); userDao = session.getMapper(IUserDao.class); accountDao = session.getMapper(IAccountDao.class); } @After public void destory() throws IOException { session.close(); is.close(); } }
3.2 一对一(多对一)关联查询,实现懒加载
需求:查询帐号信息,及其关联的用户信息
-
修改映射器接口IUserDao,增加方法findById(供关联查询时使用)
@Select("select * from user where id = #{id}") User findById(Integer id);
-
创建JavaBean:Account
注意:Account中要有User的引用,前边已经准备好
-
修改映射器接口IAccountDao,增加方法
@Select("select * from account where id = #{id}") @Results({ @Result(property = "id", column = "id", id = true), @Result(property = "uid", column = "uid"), @Result(property = "money", column = "money"), @Result( property = "user", javaType = User.class, column = "uid", one = @One( //一对一关联查询,调用select配置的statement,得到关联的User对象 select = "com.viking.dao.IUserDao.findById", //FetchType.LAZY 表示要使用延迟加载 fetchType = FetchType.LAZY ) ) }) Account findById(Integer id);
-
@Select("select * from account where id = #{id}") @Results({ @Result(property = "id", column = "id", id = true), @Result(property = "uid", column = "uid"), @Result(property = "money", column = "money"), @Result( property = "user", javaType = User.class, column = "uid", one = @One( select = "com.viking.dao.IUserDao.findById", fetchType = FetchType.LAZY ) ) }) Account findById(Integer id);
-
编写测试代码
@Test public void testOne2One(){ Account account = accountDao.findById(1); System.out.println(account.getId() + ", "+ account.getMoney()); //如果不执行下面这行代码,Mybatis不会发起查询用户的SQL System.out.println(account.getUser()); }
3.3 一对多(多对多)关联查询,实现懒加载
需求:查询用户信息,及其关联的帐号信息
-
修改映射器IAccountDao,增加方法findAccountsByUid(供关联查询时使用)
@Select("select * from account where uid = #{uid}") List<Account> findAccountsByUid(Integer uid);
-
修改JavaBean:User
注意:User中需要有Account的集合,前边已经准备好
-
修改映射器接口IUserDao,增加方法
/** * 查询用户信息,及其关联的帐号信息集合 * @param id * @return */ @Select("select * from user where id = #{id}") @Results({ @Result(property = "id",column = "id",id = true), @Result(property = "username",column = "username"), @Result(property = "birthday",column = "birthday"), @Result(property = "sex",column = "sex"), @Result(property = "address",column = "address"), @Result( property = "accounts", javaType = List.class, //注意,这里是List.class,而不是Account.class column = "id", many = @Many( //一对多关联查询,调用select对应的statement,得到帐号集合 select = "com.viking.dao.IAccountDao.findAccountsByUid", //FetchType.LAZY 表示要使用延迟加载 fetchType = FetchType.LAZY ) ) }) User findUserAccountsById(Integer id);
-
编写测试代码
@Test public void testOne2Many(){ User user = userDao.findUserAccountsById(41); System.out.println(user.getUsername()+", " + user.getAddress()); //如果不执行下面这行代码,Mybatis不会发起查询帐号的SQL语句 System.out.println(user.getAccounts()); }