Mybatis基礎概念與高級應用小結
Mybatis基礎回顧與高級應用
數(shù)據(jù)庫:mysql5.7
jdk:15
引入依賴
<!--引入依賴--> ? ?<dependencies> ? ? ? ?<!--mybatis坐標--> ? ? ? ?<dependency> ? ? ? ? ? ?<groupId>org.mybatis</groupId> ? ? ? ? ? ?<artifactId>mybatis</artifactId> ? ? ? ? ? ?<version>3.4.5</version> ? ? ? ?</dependency> ? ? ? ?<!--mysql驅動坐標--> ? ? ? ?<dependency> ? ? ? ? ? ?<groupId>mysql</groupId> ? ? ? ? ? ?<artifactId>mysql-connector-java</artifactId> ? ? ? ? ? ?<version>5.1.6</version> ? ? ? ? ? ?<scope>runtime</scope> ? ? ? ?</dependency> ? ? ? ?<!--單元測試坐標--> ? ? ? ?<dependency> ? ? ? ? ? ?<groupId>junit</groupId> ? ? ? ? ? ?<artifactId>junit</artifactId> ? ? ? ? ? ?<version>4.12</version> ? ? ? ?</dependency> ? ? ? ?<dependency> ? ? ? ? ? ?<groupId>org.projectlombok</groupId> ? ? ? ? ? ?<artifactId>lombok</artifactId> ? ? ? ? ? ?<version>1.18.22</version> ? ? ? ?</dependency> ? ?</dependencies>
User實體
@Data
public class User {
private Integer id;
private String username;
}jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1/zdy_mybatis jdbc.username=root jdbc.password=root
sqlMapConfig.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>
? ?<!--加載外部的properties文件-->
? ?<properties resource="jdbc.properties"></properties>
?
? ?<!--給實體類的全限定類名給別名-->
? ?<typeAliases>
? ? ? ?<!--給單獨的實體起別名-->
? ? <!-- ? <typeAlias type="com.yun.pojo.User" alias="user"></typeAlias>-->
? ? ? ?<!--批量起別名:該包下所有的類的本身的類名:別名還不區(qū)分大小寫-->
? ? ? ?<package name="com.yun.pojo"/>
? ?</typeAliases>
?
? ?<!--environments:運行環(huán)境-->
? ?<environments default="development">
? ? ? ?<environment id="development">
? ? ? ? ? ?<!--當前事務交由JDBC進行管理-->
? ? ? ? ? ?<transactionManager type="JDBC"></transactionManager>
? ? ? ? ? ?<!--當前使用mybatis提供的連接池-->
? ? ? ? ? ?<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>
? ? ? ?<mapper resource="UserMapper.xml"></mapper>
? ?</mappers>
</configuration>案例一-查詢用戶
UserMapper.xml
<mapper namespace="user">
<!--select-->
<select id="findAll" resultType="com.yun.pojo.User">
select * from user
</select>
</mapper>@Test
public void test1() throws IOException {
//1.Resources工具類,配置文件的加載,把配置文件加載成字節(jié)輸入流
InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
//2.解析了配置文件,并創(chuàng)建了sqlSessionFactory工廠
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.生產sqlSession
// 默認開啟一個事務,但是該事務不會自動提交
//在進行增刪改操作時,要手動提交事務
SqlSession sqlSession = sqlSessionFactory.openSession();
//4.sqlSession調用方法:查詢所有selectList 查詢單個:selectOne 添加:insert 修改:update 刪除:delete
List<User> users = sqlSession.selectList("user.findAll");
users.forEach(item ->{
System.out.println(item);
});
sqlSession.close();
?
}輸出結果
User(id=1, username=Tom)
User(id=2, username=Jerry)
案例二-添加用戶
UserMapper.xml
<!--parameterType:參數(shù)類型-->
<insert id="saveUser" parameterType="com.yun.pojo.User">
insert into user Values (#{id},#{username})
</insert>@Test
public void test2() throws IOException {
InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = new User();
user.setId(3);
user.setUsername("jack");
sqlSession.insert("user.saveUser",user);
sqlSession.commit();
sqlSession.close();
}數(shù)據(jù)庫結果:

案例三-編輯用戶
UserMapper.xml
<update id="updateUser" parameterType="com.yun.pojo.User">
update user set username = #{username} where id = #{id}
</update>@Test
public void test3() throws IOException {
InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = new User();
user.setId(3);
user.setUsername("rose");
sqlSession.update("user.updateUser",user);
sqlSession.commit();
sqlSession.close();
}數(shù)據(jù)庫結果:

案例四-刪除用戶
UserMapper.xml
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id =#{id}
</delete> @Test
public void test4() throws IOException {
InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
?
User user = new User();
user.setId(3);
sqlSession.delete("user.deleteUser",3);
sqlSession.commit();
?
sqlSession.close();
?
}數(shù)據(jù)庫結果:

傳統(tǒng)開發(fā)方式
public interface IUserDao {
?
//查詢所有用戶
List<User> findAll() throws IOException;
}UserDaoImpl
public class UserDaoImpl implements IUserDao {
?
@Override
public List<User> findAll() throws IOException {
InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> users = sqlSession.selectList("user.findAll");
sqlSession.close();
return users;
}
}@Test
public void test5() throws IOException {
UserDaoImpl dao = new UserDaoImpl();
List<User> users = dao.findAll();
System.out.println(users);
}打印結果:
[User(id=1, username=Tom), User(id=2, username=Jerry)]
代理開發(fā)方式(使用JDK動態(tài)代理產生代理對象,由代理對象執(zhí)行并且操作)
Mapper接口開發(fā)需要遵行以下規(guī)范:
mapper.xml文件中的namespace與mapper接口的全限定名相同;
2. mapper接口方法名和mapper.xml中定義的每個statement的id相同
3. mapper接口方法的輸入參數(shù)類型和mapper.xml中定義的每個sql的parameterType的類型相同
4. mapper接口方法的輸出參數(shù)類型和mapper.xml中定義的每個sql的resultType的類型相同
根據(jù)上述的規(guī)范修改UserMapper.xml
<mapper namespace="com.yun.dao.IUserDao">
?
<!--select-->
<select id="findAll" resultType="com.yun.pojo.User">
select * from user
</select>
</mapper>public interface IUserDao {
?
//查詢所有用戶
List<User> findAll() throws IOException;
}@Test
public void test6() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
?
IUserDao mapper = sqlSession.getMapper(IUserDao.class);
List<User> all = mapper.findAll();
all.forEach(item ->{
System.out.println(all);
});
}輸出結果:
User(id=1, username=Tom)
User(id=2, username=Jerry)
動態(tài)sql語句 if標簽
public interface IUserDao {
?
//多條件組合查詢:演示if
public List<User> findByCondition(User user);
}<!--抽取sql片段-->
<sql id="selectUser">
select * from user
</sql>
?
<!--多條件組合查詢:演示if-->
<select id="findByCondition" parameterType="user" resultType="user">
<include refid="selectUser"></include>
<where>
<if test="id !=null">
and id = #{id}
</if>
<if test="username !=null">
and username = #{username}
</if>
</where>
</select>@Test
public void test7() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
?
IUserDao mapper = sqlSession.getMapper(IUserDao.class);
?
User user1 = new User();
user1.setId(1);
user1.setUsername("Tom");
?
List<User> all = mapper.findByCondition(user1);
for (User user : all) {
System.out.println(user);
}
}輸出結果:
User(id=1, username=Tom)
動態(tài)sql語句 foreach標簽
public interface IUserDao {
?
//多值查詢:演示foreach
public List<User> findByIds(int[] ids);
}<!--多值查詢:演示foreach-->
<select id="findByIds" parameterType="list" resultType="user">
<include refid="selectUser"></include>
<where>
<foreach collection="array" open="id in (" close=")" item="id" separator=",">
#{id}
</foreach>
</where>
</select>@Test
public void test8() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
?
IUserDao mapper = sqlSession.getMapper(IUserDao.class);
?
int[] arr = {1,2};
?
List<User> all = mapper.findByIds(arr);
for (User user : all) {
System.out.println(user);
}
}輸出結果:
User(id=1, username=Tom)
User(id=2, username=Jerry)
Mybatis復雜映射
一對一
User實體
@Data
public class User {
?
private Integer id;
?
private String username;
?
//該用戶所具有的訂單信息
private List<Order> orders;
?
//該用戶所具有的角色信息
private List<Role> roles;
}Order實體
@Data
public class Order {
?
private Integer id;
?
private String orderTime;
?
private BigDecimal total;
?
//表明該訂單屬于哪個用戶
private User user;
}Role實體
@Data
public class Role {
?
private Integer id;
?
private String roleName;
}public interface IOrderMapper {
?
/**
* 查詢訂單的同時還查詢該訂單所屬的用戶
* @return
*/
public List<Order> findOrderAndUser();
}<resultMap id="orderMap" type="com.yun.pojo.Order">
<result property="id" column="id"></result>
<result property="orderTime" column="order_time"></result>
<result property="total" column="total"></result>
?
<association property="user" javaType="com.yun.pojo.User">
<result property="id" column="uid"></result>
<result property="username" column="username"></result>
</association>
</resultMap>
?
<!--resultMap:手動來配置實體屬性與表字段的映射關系-->
<select id="findOrderAndUser" resultMap="orderMap">
select * from orders o,user u where o.uid = u.id
</select>@Test
public void test1() throws IOException {
//1.Resources工具類,配置文件的加載,把配置文件加載成字節(jié)輸入流
InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
//2.解析了配置文件,并創(chuàng)建了sqlSessionFactory工廠
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.生產sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
IOrderMapper mapper = sqlSession.getMapper(IOrderMapper.class);
List<Order> orderAndUser = mapper.findOrderAndUser();
orderAndUser.forEach(order -> {
System.out.println(order);
});
}運行結果:
Order(id=1, orderTime=2022-05-01, total=1000.00, user=User(id=1, username=Tom, orders=null, roles=null))
Order(id=2, orderTime=2022-05-10, total=2000.00, user=User(id=2, username=Jerry, orders=null, roles=null))
Order(id=3, orderTime=2022-05-20, total=3000.00, user=User(id=2, username=Jerry, orders=null, roles=null))
一對多
public interface IUserMapper {
?
/**
* 查詢所有用戶信息,同時查詢出每個用戶關聯(lián)的訂單信息
* @return
*/
public List<User> findAll();
}<resultMap id="userMap" type="com.yun.pojo.User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
?
<collection property="orders" ofType="com.yun.pojo.Order">
<id property="id" column="oid"></id>
<result property="orderTime" column="order_time"></result>
<result property="total" column="total"></result>
</collection>
</resultMap>
?
<!--resultMap:手動來配置實體屬性與表字段的映射關系-->
<select id="findAll" resultMap="userMap">
select u.*,o.id oid,o.order_time,o.total,o.uid from user u left join orders o on u.id = o.uid
</select>@Test
public void test2() throws IOException {
//1.Resources工具類,配置文件的加載,把配置文件加載成字節(jié)輸入流
InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
//2.解析了配置文件,并創(chuàng)建了sqlSessionFactory工廠
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.生產sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
IUserMapper mapper = sqlSession.getMapper(IUserMapper.class);
List<User> users = mapper.findAll();
users.forEach(user -> {
System.out.println(user.getUsername());
System.out.println(user.getOrders());
});
}運行結果:
Tom
[Order(id=1, orderTime=2022-05-01, total=1000.00, user=null)]
Jerry
[Order(id=2, orderTime=2022-05-10, total=2000.00, user=null), Order(id=3, orderTime=2022-05-20, total=3000.00, user=null)]
多對多
public interface IUserMapper {
?
/**
* 查詢所有用戶信息,同事查詢出每個用戶關聯(lián)的角色信息
* @return
*/
public List<User> findUserAndRole();
}<resultMap id="userAndRoleMap" type="com.yun.pojo.User">
<result property="id" column="userId"></result>
<result property="username" column="username"></result>
?
<collection property="roles" ofType="com.yun.pojo.Role">
<result property="id" column="roleId"></result>
<result property="roleName" column="rolename"></result>
</collection>
</resultMap>
?
<select id="findUserAndRole" resultMap="userAndRoleMap">
SELECT * FROM USER u
LEFT JOIN sys_user_role sur ON u.id = sur.user_id
LEFT JOIN sys_role sr ON sur.role_id = sr.id
</select>@Test
public void test3() throws IOException {
//1.Resources工具類,配置文件的加載,把配置文件加載成字節(jié)輸入流
InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
//2.解析了配置文件,并創(chuàng)建了sqlSessionFactory工廠
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.生產sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
IUserMapper mapper = sqlSession.getMapper(IUserMapper.class);
List<User> users = mapper.findUserAndRole();
users.forEach(user -> {
System.out.println(user.getUsername());
System.out.println(user.getRoles());
});
}運行結果:
Tom
[Role(id=null, roleName=董事長), Role(id=null, roleName=經理)]
Jerry
[Role(id=null, roleName=董事長), Role(id=null, roleName=經理)]
Mybatis注解開發(fā)
Mybasits常用注解:
@Insert: 實現(xiàn)新增
@Update: 實現(xiàn)更新
@Delete: 實現(xiàn)刪除
@Select: 實現(xiàn)查詢
@Result: 實現(xiàn)結果集封裝;他代替的是標簽<resultMap>,該注解中可以使用單個@Result注解,也可以使用@Result集合,
使用格式:@Results({@Result(),@Result()}) 或 @Results(@Result())
@Results: 可以與@Result一起使用,封裝多個結果集
@One: 實現(xiàn)一對一結果集封裝
@Many: 實現(xiàn)一對多結果集封裝測試案例
public interface IUserMapper {
?
//添加用戶
@Insert("insert into user values(#{id},#{username})")
public void addUser(User user);
?
//更新用戶
@Update("update user set username = #{} where id = #{id}")
public void updateUser(User user);
?
//查詢用戶
@Select("select * from user")
public List<User> getAllUser();
?
//刪除用戶
@Delete("delete from user where id=#{id}")
public void delUser(Integer id);
}private IUserMapper mapper;
?
@Before
public void before() throws IOException {
//1.Resources工具類,配置文件的加載,把配置文件加載成字節(jié)輸入流
InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
//2.解析了配置文件,并創(chuàng)建了sqlSessionFactory工廠
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.生產sqlSession true:事務自動提交
SqlSession sqlSession = sqlSessionFactory.openSession(true);
mapper = sqlSession.getMapper(IUserMapper.class);
}
?
@Test
public void addUser(){
User user = new User();
user.setId(3);
user.setUsername("jack");
mapper.addUser(user);
}
?
@Test
public void updateUser(){
User user = new User();
user.setId(3);
user.setUsername("rose");
mapper.updateUser(user);
}
?
@Test
public void getAllUser(){
List<User> userList = mapper.getAllUser();
userList.forEach(item -> {
System.out.println(item);
});
}
?
@Test
public void delUser(){
mapper.delUser(3);
}運行結果:

Mybatis注解實現(xiàn)復雜映射開發(fā)
一對一
public interface IOrderMapper {
?
/**
* 查詢訂單的同時還查詢該訂單所屬的用戶
* @return
*/
@Results({
@Result(property = "id",column = "id"),
@Result(property = "orderTime",column = "order_time"),
@Result(property = "total",column = "total"),
@Result(property = "user",column = "uid",javaType = User.class,
one = @One(select = "com.yun.mapper.IUserMapper.getUserById")),
})
@Select("select * from orders")
public List<Order> findOrderAndUser();
}
?
public interface IUserMapper {
@Select("select * from user where id = #{id}")
public User getUserById(Integer id);
}@Test
public void oneToOne(){
List<Order> orderAndUser = orderMapper.findOrderAndUser();
orderAndUser.forEach(item -> {
System.out.println(item);
});
}運行結果:
Order(id=1, orderTime=2022-05-01, total=1000.00, user=User(id=1, username=Tom, orders=null, roles=null))
Order(id=2, orderTime=2022-05-10, total=2000.00, user=User(id=2, username=Jerry, orders=null, roles=null))
Order(id=3, orderTime=2022-05-20, total=3000.00, user=User(id=2, username=Jerry, orders=null, roles=null))
一對多
public interface IUserMapper {
?
/**
* 查詢所有用戶信息,同時查詢出每個用戶關聯(lián)的訂單信息
* @return
*/
@Select("select * from user")
@Results({
@Result(property = "id",column = "id"),
@Result(property = "username",column = "username"),
@Result(property = "orders",column = "id",javaType = List.class,
many = @Many(select = "com.yun.mapper.IOrderMapper.getOrderByUid"))
})
public List<User> findAll();
}
?
public interface IOrderMapper {
@Select("select * from orders where uid = #{uid}")
public List<Order> getOrderByUid(Integer uid);
}@Test
public void oneToMore(){
List<User> users = mapper.findAll();
users.forEach(item -> {
System.out.println(item);
});
?
}運行結果:
User(id=1, username=Tom, orders=[Order(id=1, orderTime=null, total=1000.00, user=null)], roles=null)
User(id=2, username=Jerry, orders=[Order(id=2, orderTime=null, total=2000.00, user=null), Order(id=3, orderTime=null, total=3000.00, user=null)], roles=null)
多對多
public interface IUserMapper {
/**
* 查詢所有用戶信息,同事查詢出每個用戶關聯(lián)的角色信息
* @return
*/
@Select("select * from user")
@Results({
@Result(property = "id",column = "id"),
@Result(property = "username",column = "username"),
@Result(property = "roles",column = "id",javaType = List.class,
many = @Many(select ="com.yun.mapper.IRoleMapper.getAll"))
})
public List<User> findUserAndRole();
}
?
public interface IRoleMapper {
?
@Select("select * from sys_role sr,sys_user_role sur where sr.id = sur.role_id and sur.user_id = #{uid}")
public List<Role> getAll(Integer uid);
}@Test
public void moreToMore(){
List<User> users = mapper.findUserAndRole();
users.forEach(item -> {
System.out.println(item);
});
}運行結果:
User(id=1, username=Tom, orders=null, roles=[Role(id=1, roleName=董事長), Role(id=2, roleName=經理)])
User(id=2, username=Jerry, orders=null, roles=[Role(id=1, roleName=董事長), Role(id=2, roleName=經理)])
Mybatis緩存
基礎概念

緩存就是內存中的數(shù)據(jù),常常來自對數(shù)據(jù)庫查詢結果的保存,使用緩存,我們可以避免頻繁的與數(shù)據(jù)庫進行交互,進而提高響應速度.
一級緩存是SqlSession,在操作數(shù)據(jù)庫時需要構造sqlSession對象,在對象中有一個數(shù)據(jù)結構(HashMap)用于存儲緩存數(shù)據(jù).不同的sqlSession之間互不影響.
二級緩存是mapper級別的緩存,多個sqlSession去操作同一個mapper的sql語句,多個sqlSession可以共用二級緩存,二級緩存是跨sqlSession的.
一級緩存
demo
public class CacheTest {
?
private IUserMapper mapper;
private SqlSession sqlSession;
?
@Before
public void before() throws IOException {
//1.Resources工具類,配置文件的加載,把配置文件加載成字節(jié)輸入流
InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
//2.解析了配置文件,并創(chuàng)建了sqlSessionFactory工廠
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.生產sqlSession true:事務自動提交
sqlSession = sqlSessionFactory.openSession(true);
mapper = sqlSession.getMapper(IUserMapper.class);
}
?
@Test
public void test1() {
?
//第一次查詢id為1的用戶
User user1 = mapper.getUserById(1);
?
//第二次查詢id為1的用戶
User user2 = mapper.getUserById(1);
?
System.out.println(user1 == user2);
}
}返回結果為 true ;測試一級緩存是默認開啟的
結論:第一次發(fā)起查詢用戶id為1的用戶信息,先去找緩存中是否有id為1的用戶,如果沒有,則從數(shù)據(jù)庫查詢用戶信息,得到用戶信息并且將用戶信息存儲到一級緩存中,第二次發(fā)起查詢用戶id為1的用戶信息,先去找緩存中是否有id為1的用戶,如果緩存中有,直接從緩存中獲取用戶信息;
現(xiàn)在我們變換一下上面的demo
public class CacheTest {
?
private IUserMapper mapper;
private SqlSession sqlSession;
?
@Before
public void before() throws IOException {
//1.Resources工具類,配置文件的加載,把配置文件加載成字節(jié)輸入流
InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
//2.解析了配置文件,并創(chuàng)建了sqlSessionFactory工廠
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.生產sqlSession true:事務自動提交
sqlSession = sqlSessionFactory.openSession();
mapper = sqlSession.getMapper(IUserMapper.class);
}
?
@Test
public void test1() {
?
//第一次查詢id為1的用戶
User user1 = mapper.getUserById(1);
?
User user = new User();
user.setId(1);
user.setUsername("Lucy");
mapper.updateUser(user);
?
sqlSession.commit();
?
//第二次查詢id為1的用戶
User user2 = mapper.getUserById(1);
?
System.out.println(user1 == user2);
}
}返回結果為 false
結論:做增刪改操作,并進行了事物的提交,就會刷新以及緩存;或者還可以通過 sqlSession.clearCache()清楚緩存;這樣做的目的就是為了讓緩存中存儲的是最新的信息,避免臟讀;
二級緩存
二級緩存的原理和一級緩存原理一樣,第一次查詢會將數(shù)據(jù)放入緩存中,然后第二次查詢則會直接從緩存中獲取,但是一級緩存是基于sqlSession的,而二級緩存是基于mapper文件的namespace,也就是說,多個sqlSession可以共享一個mapper中的二級緩存,并且如果兩個mapper的namespace相同,即使是兩個mapper,那么這兩個mapper執(zhí)行sql查詢到的數(shù)據(jù)也將存在相同的二級緩存區(qū)域中.

如何使用二級緩存
首先在全局配置文件sqlMapconfig.xml文件加入如下代碼
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>注意,該配置需要放在properties標簽下,具體順序,可百度了解
其次,在xxxMapper.xml文件中開啟緩存(如果當前操作時基于注解開發(fā)的話,使用注解@CacheNamespace)
<cache></cache>
demo2
public class CacheTest {
?
? ?private IUserMapper mapper;
? ?private SqlSession sqlSession;
? ?private SqlSessionFactory sqlSessionFactory;
?
? ?@Before
? ?public void before() throws IOException {
? ? ? ?//1.Resources工具類,配置文件的加載,把配置文件加載成字節(jié)輸入流
? ? ? ?InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
? ? ? ?//2.解析了配置文件,并創(chuàng)建了sqlSessionFactory工廠
? ? ? ?sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
? ? ? ?//3.生產sqlSession
? ? ? ?sqlSession = sqlSessionFactory.openSession();
? ? ? ?mapper = sqlSession.getMapper(IUserMapper.class);
? }
?
? ?@Test
? ?public void test2() {
?
? ? ? ?SqlSession sqlSession1 = sqlSessionFactory.openSession();
? ? ? ?SqlSession sqlSession2 = sqlSessionFactory.openSession();
? ? ? ?SqlSession sqlSession3 = sqlSessionFactory.openSession();
?
? ? ? ?IUserMapper mapper1 = sqlSession1.getMapper(IUserMapper.class);
? ? ? ?IUserMapper mapper2 = sqlSession2.getMapper(IUserMapper.class);
? ? ? ?IUserMapper mapper3 = sqlSession3.getMapper(IUserMapper.class);
?
? ? ? ?User user1 = mapper1.getUserById(1);
? ? ? ?//清空一級緩存
? ? ? ?sqlSession1.close();
? ? ? ?User user2 = mapper2.getUserById(1);
?
? ? ? ?System.out.println(user1 == user2);
? }
}運行結果為 false
結論:通過debug斷點顯示,實際上,第二次查詢則會直接從緩存中獲取用戶信息了,不過二級緩存緩存的不是對象,而是緩存的對象中的數(shù)據(jù),所以查詢結果為false;
注意,二級緩存底層還是HashMap結構,所以 po類需要實現(xiàn)序列化接口 ;因為二級緩存數(shù)據(jù)存儲介質多種多樣,不一定只存在內存中,有可能存在硬盤中,如果我們要在取這個緩存的話,就需要反序列化了,所以mybatis中的pojo都去實現(xiàn)Serializable接口;
變換一下demo2
@Test
public void test2() {
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
SqlSession sqlSession3 = sqlSessionFactory.openSession();
IUserMapper mapper1 = sqlSession1.getMapper(IUserMapper.class);
IUserMapper mapper2 = sqlSession2.getMapper(IUserMapper.class);
IUserMapper mapper3 = sqlSession3.getMapper(IUserMapper.class);
User user1 = mapper1.getUserById(1);
//清空一級緩存
sqlSession1.close();
User user = new User();
user.setId(1);
user.setUsername("Tom");
mapper3.updateUser(user);
sqlSession3.commit();
User user2 = mapper2.getUserById(1);
System.out.println(user1 == user2);
}返回結果為 false
結論:做增刪改操作,并進行了事物的提交,就會刷新以及緩存;這樣做的目的就是為了讓緩存中存儲的是最新的信息,避免臟讀;
此外mybatis中還可以配置useCache和flushCache等配置項;
useCache
是用來設置是否禁用二級緩存的,在statement中設置useCache=false可以禁用當前select語句的二級緩存,即每次查詢都會會發(fā)出sql去查詢,默認情況是true,即該sql使用二級緩存,例如
<select id="findAll" useCache = "false" resultMap="userMap">
select u.*,o.id oid,o.order_time,o.total,o.uid from user u left join orders o on u.id = o.uid
</select>使用sql注解方式可以使用@Options(useCache = false)的方式
flushCache
在mapper的同一個namespace中,如果有其他的insert,update,delete操作數(shù)據(jù)后需要刷新緩存,如果不執(zhí)行刷新緩存會出現(xiàn)臟讀,設置statememt配置中的
flushCache = "true"屬性,默認情況下為true,即刷新緩存,如果改成false則不會刷新,使用緩存時如果手動修改數(shù)據(jù)庫表中的查詢數(shù)據(jù)會出現(xiàn)臟讀 例如
<select id="findAll" flushCache = "true" useCache = "false" resultMap="userMap">
select u.*,o.id oid,o.order_time,o.total,o.uid from user u left join orders o on u.id = o.uid
</select>一般下執(zhí)行完commit操作都需要刷新緩存,flushCache=true表示刷新緩存,這樣可以避免數(shù)據(jù)庫臟讀,所以我們不用設置,默認即可
至此,mybatis基礎概念及應用回顧完成!
到此這篇關于Mybatis基礎回顧與高級應用的文章就介紹到這了,更多相關Mybatis高級應用內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringSecurity OAtu2+JWT實現(xiàn)微服務版本的單點登錄的示例
本文主要介紹了SpringSecurity OAtu2+JWT實現(xiàn)微服務版本的單點登錄的示例,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-05-05
java.lang.UnsatisfiedLinkError: %1 不是有效的Win32應用程序錯誤解決
這篇文章主要給大家介紹了關于java.lang.UnsatisfiedLinkError: %1 不是有效的Win32應用程序錯誤的解決方法,文中介紹的非常詳細,需要的朋友們可以參考學習,下面來一起看看吧。2017-03-03
詳解springMVC之與json數(shù)據(jù)交互方法
本篇文章主要介紹了詳解springMVC之與json數(shù)據(jù)交互方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-05-05

