目录
延迟加载
- 延迟加载:使用数据时才发起查询,不用的时候不查询,按需查询 ,通常用在一对多、多对多(对多操作)
- 立即加载:不管用不用,只要一调用方法,马上发起查询,通常用在一对一、多对一(对一操作)
一对一实现延迟加载
account 与user的关系是一对多
assocation实现延迟加载
- select:填写我们需要调用的select映射的id
- column:填写我们需要传递给select映射的参数
核心配置文件:配置延时加载
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
user表:
public interface Iuser {
user findById(int id);
}
<?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.dome2.dao.Iuser">
<select id="findById" resultType="user" parameterType="int">
select * from user where id=#{id}
</select>
</mapper>
account表:
public interface Iaccount {
List<account>findAll_t3();
}
<?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">
<resultMap id="account_1" type="account">
<id property="ID" column="ID"/>
<result property="UID" column="UID"/>
<result property="MONEY" column="MONEY"/>
<!-- 可以理解为将uid的参数传入Iuser的findById中 -->
<association property="user" javaType="user" select="com.dome2.dao.Iuser.findById" column="uid"/>
</resultMap>
<select id="findAll_t3" resultMap="account_1">
select * from account
</select>
</mapper>
运行结果:
获取查询的结果集 并且遍历
因为需要对user进行查询,所以查询到uid后,会对user进行查询(延时加载)
获取查询的结果集 不遍历(不需要对user进行查询)
如果不对user进行查询等操作,则不会对其加载
一对多的延时加载
user对account是一对多
使用collection实现延时加载
select、colum属性与assocation的属性一样
account表:
public interface Iaccount {
List<account>findById(int id);
}
<?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.dome2.dao.Iaccount">
<select id="findById" parameterType="int" resultType="account">
select * from account where uid=#{id}
</select>
</mapper>
user表:
public interface Iuser {
List<user> findAll_1();
}
<?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.dome2.dao.Iuser">
<resultMap id="rm" type="user">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="address" column="address"/>
<result property="sex" column="sex"/>
<result property="birthday" column="birthday"/>
<collection property="list" ofType="account" select="com.dome2.dao.Iaccount.findById" column="id"/>
</resultMap>
<select id="findAll_1" resultMap="rm">
select * from user
</select>
</mapper>
运行结果
获取结果集 并且遍历
通过获取的id进行account的查询
获取结果集 不遍历(不需要对account进行加载)
Mybatis缓存
原理图
一级缓存存储的是对象;二级缓存存储的是数据
一级缓存
该缓存是sqlseesion的范围的缓存,当调用SqlSession的修改、添加、删除,commit()、close()等方法时,就会清空缓存。
当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供一块区域中。该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去sqlsession中查询是否有,有的话直接拿出来用。当SqlSession对象消失时,mybatis的一级缓存也就消失了。
示例代码
使用同一个SqlSession对象时,第一次查询会将查询结果存入缓存中,第二次查询直接从缓存中取
user byId = iuser.findById(44);
user byId1 = iuser.findById(44);
System.out.println(byId==byId1);//true
清空SqlSession缓存后的运行结果
user byId = iuser.findById(41);
// 清空缓存
sqlSession.clearCache();
// 重新获取代理对象
iuser = sqlSession.getMapper(Iuser.class);
user byId1 = iuser.findById(41);
System.out.println(byId==byId1);//false
二级缓存
SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。
步骤
- 让Mybatis框架支持二级缓存(在SqlMapnConfig.xml中配置)
- 让当前的映射文件支持二级缓存(映射文件)
- 让当前的操作支持二级缓存(在select标签中配置)
示例代码
主配置文件
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
user的映射文件
<?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.dome2.dao.Iuser">
<!-- 开启二级缓存-->
<cache/>
<!-- userCache 开启二级缓存-->
<select id="findById" resultType="user" parameterType="int" useCache="true">
select * from user where id=#{id}
</select>
<resultMap id="rm" type="user">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="address" column="address"/>
<result property="sex" column="sex"/>
<result property="birthday" column="birthday"/>
<collection property="list" ofType="account" select="com.dome2.dao.Iaccount.findById" column="id"/>
</resultMap>
<select id="findAll_1" resultMap="rm">
select * from user
</select>
</mapper>
测试代码:
SqlSession sqlSession = factory.openSession();
Iuser mapper = sqlSession.getMapper(Iuser.class);
user byId = mapper.findById(41);
System.out.println(byId);
// 一级缓存消失
sqlSession.close();
SqlSession sqlSession1 = factory.openSession();
Iuser mapper1 = sqlSession1.getMapper(Iuser.class);
user byId1 = mapper1.findById(41);
System.out.println(byId1);
sqlSession1.close();
System.out.println(byId==byId1);
同一个SqlFactory 下不同的SqlSession
运行结果
从图片可以看出,只执行了一次sql语句,输出false的原因,二级缓存存储的是数据不是对象
Mybatis注解开发
作用:省去了编写接口映射文件的时间
注解名称 | 含义 |
@Select | 进行查询 |
@Insert | 进行增加 |
@Delete | 进行删除 |
@Update | 进行修改 |
@Results | 可以进行复杂关系映射 内部可以使用多个@Result |
@Result | 可以进行详细的关系映射 |
@One | 替代了assocation标签,可以进行一对一查询 |
@Many | 替代了collestion标签,可以进行一对多查询 |
@Result的属性
- id:是否为主键
- column:数据库的表名
- property:类的成员属性
- one:需要使用@One注解
- many:需要使用@Many注解
案例:CRUD实现注解开发
接口:
public interface Iuser {
// 增加
@Insert("insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})")
void insert(user u);
// 删
@Delete("delete from user where id=#{id}")
void delete(int id);
@Update("update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address}where id=#{id}")
// 改
void update(user u);
// 查
// 所有
@Select("select * from user")
List<user> FindAll();
// 根据id查询
@Select("select * from user where id=#{id}")
user FindById(int id);
// 根据name模糊查询
@Select("select * from user where username like #{name}")
List<user> FindByName(String name);
// 查询聚合函数
@Select("select count(id) from user")
int count();
}
在核心配置文件中导入接口
<mappers>
<!-- 导入该接口-->
<!-- <mapper class="com.dao.Iuser"/>-->
<!-- 注册包内所有接口-->
<package name="com.dao"/>
</mappers>
复杂映射
当实体类的属性名和数据库的列名不一致时,需要复杂映射
实体类:
@Setter @Getter @ToString
public class AUser {
private int Aid;
private String Ausername;
private Date Abirthday;
private String Asex;
private String Aaddress;
}
接口:
@Insert("insert into user(username,birthday,sex,address) values(#{Ausername},#{Abirthday},#{Asex},#{Aaddress})")
@Results(id = "userMap",value = {
@Result(id = true, column = "id",property ="Aid" ),
@Result(column = "username",property = "Ausername"),
@Result(column = "birthday",property = "Abirthday"),
@Result(column = "sex",property = "Asex"),
@Result(column = "address",property = "Aaddress")
})
void insert(AUser u);
案例:一对一查询
account表与user表的关系是一对一
account表:
@Setter @Getter @ToString
public class account {
private int ID;
private int UID;
private double MONEY;
// account 对 user 是1对1
private user user;
}
接口:
public interface Iaccount {
@Select("select * from account")
@Results({
@Result(id = true,column = "ID",property ="ID" ),
@Result(column = "MONEY",property = "MONEY"),
@Result(column = "UID",property = "UID"),
@Result(column = "UID" ,property = "user",
one = @One(select = "com.dao.Iuser.FindById",fetchType = FetchType.LAZY))
// FetchType.LAZY:延时加载
})
List<account> findAll();
}
@One注解:将UID参数传入Iuser接口的FindById方法中进行查询,并且返回结果
案例:一对多查询
user与account的关系是一对多
user表:
@Setter @Getter @ToString
public class user {
private int id;
private String username;
private Date birthday;
private String sex;
private String address;
// user 与account 的关系是一对多
private List<account> list;
}
接口:
public interface Iuser {
@Select("select * from user")
@Results(
{
@Result(id = true,column = "id",property = "id"),
@Result(column = "username",property = "username"),
@Result(column = "birthday",property = "birthday"),
@Result(column = "sex",property = "sex"),
@Result(column = "address",property = "address"),
@Result(column = "id",property = "list", many = @Many(select = "com.dao.Iaccount.findByID",fetchType = FetchType.LAZY)
)
}
)
List<user> FindAll_t1();
}
@Many注解:将id参数传入Iaccount的findByID方法 ,并且将结果传回
基于注解设置二级缓存
步骤:
- 在核心文件中开启二级缓存支持
- 在持久层接口中配置二级缓存
示例代码:
核心配置文件添加代码:
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
持久层接口配置二级缓存
@CacheNamespace(blocking = true)
public interface Iaccount {...}
运行结果
从图中可以看出,sql代码只执行了一次