08- MyBatis进阶
2021-02-14 本文已影响0人
XAbo
一、MyBatis的延迟加载
- 一对多,多对多:通常情况下我们都是采用延迟加载。
- 多对一,一对一:通常情况下我们都是采用立即加载。
开启延迟加载mybatis-config.xml
<?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>
<!--配置参数-->
<settings>
<!--开启Mybatis支持延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--开启时,任何方法的调用都会加载该对象的所有属性,否则按需加载。-->
<setting name="aggressiveLazyLoading" value="false"></setting>
</settings>
<!--使用typeAliases配置别名,只能配置domain中类的别名-->
<typeAliases>
<package name="com.example.domain"></package>
</typeAliases>
<properties resource="jdbc.properties"></properties>
<!--配置环境-->
<environments default="development">
<environment id="development">
<!-- 配置事务类型 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置数据源(连接池) -->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- 指定映射文件 -->
<mappers>
<package name="com.example.dao"></package>
</mappers>
</configuration>
1.1 一对一
没有延迟加载:AccountMapper.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.example.dao.AccountDao">
<resultMap id ="accountUserMap" type ="account">
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!--配置一对一-->
<association property="user" column="uid" javaype="com.example.domain.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>
</association>
</resultMap>
<select id="findAll" resultMap="accountUserMap">
select u.*,a.id as aid ,a.uid ,a.money from [Account] a ,[User] u where u.id = a.uid
</select>
</mapper>
使用延迟加载:AccountMapper.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.example.dao.AccountDao">
<resultMap id ="accountUserMap" type ="account">
<id property="id" column="id"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!--配置一对一-->
<association property="user" column="uid" javaType="com.example.domain.User"
select="com.example.dao.UserDao.FindById">
</resultMap>
<select id="findAll" resultMap="accountUserMap">
select * from [Account]
</select>
</mapper>
UserMapper.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.example.dao.UserDao">
<resultMap id ="userAccountMap" 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="com.example.domain.Account">
<id property="aid" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
</collection>
</resultMap>
<select id="findAll" resultMap="userAccountMap">
select * from [User] u left join Accout a on u.id = a.uid
</select>
<select id="findById" parameterType= "INT" resultType="user">
select * from [User] where id = ${id}
</select>
</mapper>
1.2 一对多
使用延迟加载:UserMapper.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.example.dao.UserDao">
<resultMap id ="userAccountMap" 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="com.example.domain.Account"
select="com.example.dao.Account.findAccountByUid" column="id">
</collection>
</resultMap>
<select id="findAll" resultMap="userAccountMap">
select * from [User]
</select>
<select id="findById" parameterType= "INT" resultType="user">
select * from [User] where id = ${id}
</select>
</mapper>
AccountMapper.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.example.dao.AccountDao">
<resultMap id ="accountUserMap" type ="account">
<id property="id" column="id"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!--配置一对一-->
<association property="user" column="uid" javaType="com.example.domain.User"
select="com.example.dao.UserDao.FindById">
</resultMap>
<select id="findAll" resultMap="accountUserMap">
select * from [Account]
</select>
<select id="findAccountByUid" resultType="account">
select * from [Account] where uid=#{uid}
</select>
</mapper>
二、MyBatis的缓存
2.1 一级缓存
一级缓存:它指的是Mybatis中SqlSession对象的缓存。当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供一块区域中。该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去sqlsession中查询是否有,有的话直接拿出来用。当SqlSession对象消失时,mybatis的一级缓存也就消失了。默认是开启的。
调用SqlSession的修改、添加、删除、提交和关闭等方法时候,一级缓存就会被清空。
@Test
public void testFirstLevelCache() {
User u1 = userDao.findById(1);
User u2 = userDao.findById(1);
System.out.println(u1==u2);
}
结果:true。
2.2 二级缓存
二级缓存:它指的是Mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。
二级缓存- 第一步:让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
- 第二步:让当前的映射文件支持二级缓存(在UserDao.xml中配置)
- 第三步:让当前的操作支持二级缓存(在select标签中配置)
<mapper namespace="com.example.dao.UserDao">
<cache/>
<select id="findById" parameterType= "INT" resultType="user" useCache="true">
select * from [User] where id = ${id}
</select>
</mapper>
客户端:
@Test
public void testSecondLevelCache() {
SqlSession sqlSession1 = factory.openSession();
UserDao dao1 = sqlSession1.gerMapper(UserDao.class);
User u1 = dao1 .findById(1);
sqlSession1.close(); // 一级缓存关闭
SqlSession sqlSession2 = factory.openSession();
UserDao dao2 = sqlSession2.gerMapper(UserDao.class);
User u2 = dao2 .findById(1);
sqlSession2.close(); // 一级缓存关闭
System.out.println(u1==u2); // false
}
sql仅执行一次
三、MyBatis注解(了解)
MyBatis的主配置文件不变,仅修改mapper.xml。
@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
@Results:可以与@Result 一起使用,封装多个结果集
@ResultMap:实现引用@Results 定义的封装
@One:实现一对一结果集封装
@Many:实现一对多结果集封装
@SelectProvider: 实现动态SQL映射
@CacheNamespace:实现注解二级缓存的使用
3.1 基础应用
UserDao:
public interface UserDao {
@Select("select * from user")
List<User> findAll();
@Insert("insert into user(username,address,sex,birthday)values(#{username},#{address},#{sex},#{birthday})")
void saveUser(User user);
@Update("update user set username=#{username},sex=#{sex},birthday=#{birthday},address=#{address} where id=#{id}")
void updateUser(User user);
@Delete("delete from user where id=#{id} ")
void deleteUser(Integer userId);
@Select("select * from user where id=#{id} ")
User findById(Integer userId);
// @Select("select * from user where username like #{username} ")
@Select("select * from user where username like '%${value}%' ")
List<User> findUserByName(String username);
@Select("select count(*) from user ")
int findTotalUser();
}
3.2 复杂应用
实现复杂关系映射之前我们可以在映射文件中通过配置<resultMap>来实现,在使用注解开发时我们需要借助@Results
注解,@Result
注解,@One
注解,@Many
注解。
@Results 注解代替的是标签<resultMap> ;该注解中可以使用单个@Result 注解,
也可以使用@Result集合 @Results({@Result(),@Result()})或@Results(@Result())
@Result 注解代替了<id>标签和<result>标签
@Result 中属性介绍: id是否是主键字段;column 数据库的列名;property需要装配的属性名
one 需要使用的@One 注解(@Result(one=@One)()))
many 需要使用的@Many 注解(@Result(many=@many)()))
@One 注解(一对一) 代替了<assocation>标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
@One 注解属性介绍:
select指定用来多表查询的sqlmapper fetchType会覆盖全局的配置参数 lazyLoadingEnabled。
使用格式: @Result(column=" ",property="",one=@One(select=""))
@Many 注解(多对一)代替了<Collection>标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。
注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,
属性的 javaType (一般为 ArrayList)但是注解中可以不定义;
使用格式: @Result(property="",column="",many=@Many(select=""))
3.2.1 一对一
AccountDao:
public interface AccountDao {
@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 = #{userId}")
List<Account> findAccountByUid(Integer userId);
}
UserDao:
@CacheNamespace(blocking = true)
public interface UserDao {
@Select("select * from user")
@Results(id="userMap",value={
@Result(id=true,column = "id",property = "userId"),
@Result(column = "username",property = "userName"),
@Result(column = "address",property = "userAddress"),
@Result(column = "sex",property = "userSex"),
@Result(column = "birthday",property = "userBirthday"),
@Result(property = "accounts",column = "id",
many = @Many(select = "com.itheima.dao.IAccountDao.findAccountByUid",
fetchType = FetchType.LAZY))
})
List<User> findAll();
@Select("select * from user where id=#{id} ")
@ResultMap("userMap")
User findById(Integer userId);
@Select("select * from user where username like #{username} ")
@ResultMap("userMap")
List<User> findUserByName(String username);
}
3.2.2 一对多
UserDao:
@CacheNamespace(blocking = true)
public interface UserDao {
@Select("select * from user")
@Results(id="userMap",value={
@Result(id=true,column = "id",property = "userId"),
@Result(column = "username",property = "userName"),
@Result(column = "address",property = "userAddress"),
@Result(column = "sex",property = "userSex"),
@Result(column = "birthday",property = "userBirthday"),
@Result(property = "accounts",column = "id",
many = @Many(select = "com.itheima.dao.IAccountDao.findAccountByUid",
fetchType = FetchType.LAZY))
})
List<User> findAll();
@Select("select * from user where id=#{id} ")
@ResultMap("userMap")
User findById(Integer userId);
@Select("select * from user where username like #{username} ")
@ResultMap("userMap")
List<User> findUserByName(String username);
}