java ssm框架 缓存_SSM框架之Mybatis(7)延迟加载、缓存及注解
Mybatis(7)延遲加載、緩存及注解
1、延遲加載
延遲加載:
就是在需要用到數據時才進行加載,不需要用到數據時就不加載數據。延遲加載也稱懶加載.
**好處:**先從單表查詢,需要時再從關聯表去關聯查詢,大大提高數據庫性能,因為查詢單表要比關聯查詢多張表速
度要快。
壞處 :
因為只有當需要用到數據時,才會進行數據庫查詢,這樣在大批量數據查詢時,因為查詢工作也要消耗
時間,所以可能造成用戶等待時間變長,造成用戶體驗下降
2、Mybatis緩存
?像大多數的持久化框架一樣,Mybatis 也提供了緩存策略,通過緩存策略來減少數據庫的查詢次數,從而提
高性能。
Mybatis 中緩存分為一級緩存,二級緩存。
2.1、一級緩存
一級緩存是SqlSession級別的緩存,只要SqlSession沒有flush、close或clearCache,那么緩存就會存在。
2.1.1、測試一級緩存的存在
測試方法
@Test
public void testFindOne(){
//通過id查找用戶
User user1 = uesrdao.findById(48);
System.out.println(user1.hashCode());
//sqlSession.clearCache();
User user2 = uesrdao.findById(48);
System.out.println(user2.hashCode());
System.out.println(user1 == user2);
}
運行結果:
Opening JDBC Connection
Created connection 278934944.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@10a035a0]
==> Preparing: select * from user where id=?
> Parameters: 48(Integer)
< Total: 1
1832580921
1832580921
true
分析
上面的結果顯示雖然我們進行了兩次查詢,但是只執行了一次數據庫操作。這就是一級緩存在起作用,因為一級緩存的存在所以在第二次查詢id = 48時,沒有進行數據庫的操作,而是直接從一級緩存中讀取數據。
2.1.2、一級緩存
一級緩存是SqlSession級別的緩存,當調用SqlSession緩存的 添加,更新、刪除、commit()、close()等操作時,會清空一級緩存。
第一次sqlsession對象執行查詢操作id = 48時,先去緩存中查詢是否存在有id=48的用戶信息,沒有就執行sql語句,然后從數據庫中查詢數據。
得到用戶信息后就把用戶信息儲存在一級緩存中。
準確來說,存入一級緩存的是由查詢語句返回的對象,而不是具體的數據
第二次發起查詢用戶 id 為 1 的用戶信息,先去找緩存中是否有 id 為 1 的用戶信息,緩存中有,直接從緩存
中獲取用戶信息。
如果 sqlSession 去執行 commit 操作(執行插入、更新、刪除),清空 SqlSession 中的一級緩存,這樣
做的目的為了讓緩存中存儲的是最新的信息,避免臟讀。
2.1.3、對清除緩存的操作
@Test
public void testFindOne(){
//通過id查找用戶
User user1 = uesrdao.findById(48);
System.out.println(user1.hashCode());
sqlSession.clearCache();
User user2 = uesrdao.findById(48);
System.out.println(user2.hashCode());
System.out.println(user1 == user2);
}
執行結果:
Opening JDBC Connection
Created connection 278934944.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@10a035a0]
==> Preparing: select * from user where id=?
> Parameters: 48(Integer)
< Total: 1
1832580921
==> Preparing: select * from user where id=?
> Parameters: 48(Integer)
< Total: 1
369241501
false
清空緩存后查詢數據庫的信息,查詢了兩次。
2.2、二級緩存
二級緩存是 mapper 映射級別的緩存,多個 SqlSession 去操作同一個 Mapper 映射的 sql 語句,多個
SqlSession 可以共用二級緩存,二級緩存是跨 SqlSession 的。
及可以認為二級緩存是依賴于SqlSessionFactory,SqlSessionFactory對象產生時,就存在,并且由同一個SqlSessionFactory對象創建的SqlSession共享其緩存。
二級緩存的使用步驟:
第一步:讓Mybatis框架支持二級緩存(在SqlMapConfig.xml中配置)在configuration標簽中開啟setting標簽
setting標簽
設置名
描述
有效值
默認值
cacheEnabled
全局地開啟或關閉配置文件中的所有映射器已經配置的任何緩存。
true | false
true
因為 cacheEnabled 的取值默認就為 true,所以這一步可以省略不配置。為 true 代表開啟二級緩存;為
false 代表不開啟二級緩存。
第二步:讓當前的映射文件支持二級緩存(在IUserDao.xml中配置)
在mapper標簽中寫
cache標簽表示當前這個 mapper 映射將使用二級緩存,區分的標準就看 mapper 的 namespace 值。
第三步:讓當前的操作支持二級緩存(在select標簽中配置)
在mapper標簽中寫
select * from user where id=#{id}
將 UserDao.xml 映射文件中的select標簽中設置 useCache=”true”代表當前這個 statement 要使用
二級緩存,如果不使用二級緩存可以設置為 false。
注意:針對每次查詢都需要最新的數據 sql,要設置成 useCache=false,禁用二級緩存。
第四步:添加測試類
package test;
import dao.IUserDao;
import domain.QueryVo;
import 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 CacheTest {
/**
* 測試mybatis的CRUD操作
*/
InputStream in;
SqlSessionFactory build;
@Before
public void init() throws Exception {
in = Resources.getResourceAsStream("SqlMapConfig.xml");
build = new SqlSessionFactoryBuilder().build(in);
}
@After
public void destory() throws Exception {
in.close();
}
@Test
public void testFindOne(){
SqlSession sqlSession1 = build.openSession();
IUserDao dao1 = sqlSession1.getMapper(IUserDao.class);
User user1 = dao1.findById(41);
System.out.println(user1);
sqlSession1.close();//一級緩存消失
SqlSession sqlSession2 = build.openSession();
IUserDao dao2 = sqlSession2.getMapper(IUserDao.class);
User user2 = dao2.findById(41);
System.out.println(user2);
sqlSession2.close();
System.out.println(user1 == user2);
}
}
執行結果:
Opening JDBC Connection
Created connection 929776179.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@376b4233]
==> Preparing: select * from user where id=?
> Parameters: 41(Integer)
< Total: 1
User{id=41, username=‘老王’, birthday=Tue Feb 27 17:47:08 CST 2018, sex=‘男’, address=‘北京’}
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@376b4233]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@376b4233]
Returned connection 929776179 to pool.
Cache Hit Ratio [dao.IUserDao]: 0.5
User{id=41, username=‘老王’, birthday=Tue Feb 27 17:47:08 CST 2018, sex=‘男’, address=‘北京’}
false
經過上面的測試,我們發現執行了兩次查詢,并且在執行第一次查詢后,我們關閉了一級緩存,再去執行第二
次查詢時,我們發現并沒有對數據庫發出 sql 語句,所以此時的數據就只能是來自于我們所說的二級緩存。
然而兩次的User對象卻不相同,這是因為二級緩存存儲的是對應的具體數據
{id=41, username=‘老王’, birthday=Tue Feb 27 17:47:08 CST 2018, sex=‘男’, address=‘北京’}
等到再次查詢時才會new新的對象。
2.2.1、二級緩存的注意事項
當我們在使用二級緩存時,所緩存的類一定要實現 java.io.Serializable 接口,這種就可以使用序列化
方式來保存對象。
/**
*
*
Title: User
*
Description: 用戶的實體類
*/
public class User implements Serializable {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
}
3、Mybatis關于注解的開發
3.1、mybatis常用注解說明
@Insert:實現新增
@Update:實現更新
@Delete:實現刪除
@Select:實現查詢
@Result:實現結果集封裝
@Results:可以與@Result 一起使用,封裝多個結果集
@ResultMap:實現引用@Results 定義的封裝
@One:實現一對一結果集封裝
@Many:實現一對多結果集封裝
@SelectProvider: 實現動態 SQL 映射
@CacheNamespace:實現注解二級緩存的使用
3.2、用注解實現CRUD操作
3.2.1、編寫實體類
E:\java\idea\SSM\ssm01_mybatis_annotation\src\main\java\domain\User.java
package domain;
import java.io.Serializable;
import java.util.Date;
public class User implements Serializable {
private Integer id;
private String username;
private String address;
private String sex;
private Date 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 getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", address='" + address + '\'' +
", sex='" + sex + '\'' +
", birthday=" + birthday +
'}';
}
}
3.2.2、編寫主配置文件
E:\java\idea\SSM\ssm01_mybatis_annotation\src\main\resources\SqlMapConfig.xml
/p>
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
3.2.3、編寫持久化接口
E:\java\idea\SSM\ssm01_mybatis_annotation\src\main\java\dao\IUserDao.java
package dao;
import domain.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
/**
* 在mybatis中針對注解有四個注解
*@Select()、@Insert()、@Update()、@Delete()
*/
@CacheNamespace(blocking = true)
public interface IUserDao {
/**
* 查詢所有
* @return
*/
@Select(value = "select * from user")
List findAll();
/**
* 添加用戶
* @param user
*/
@Insert("insert into user (username,address,sex,birthday) values(#{username},#{address},#{sex},#{birthday})")
void addUser(User user);
/**
* 根據id刪除指定用戶
* @param id
*/
@Delete("delete from user where id = #{id}")
void deleteUser(int id);
/**
* 更新用戶數據
* @param user
*/
@Update("update user set username = #{username},address = #{address},sex = #{sex},birthday = #{birthday} where id = #{id}")
void updateUser(User user);
@Select("select * from user where id = #{id}")
User findById(int id);
/**
* 模糊查詢
* @param name
* @return
*/
//@Select("select * from user where username like #{str}")
@Select("select * from user where username like '%${value}%'")
List findByName(String name);
/**
*
* @return
*/
@Select("select count(id) from user")
int findTotal();
}
3.2.4、編寫相應測試類
package test;
import dao.IUserDao;
import 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 AnnotationTest {
InputStream in;
SqlSessionFactory factory;
SqlSession sqlSession;
IUserDao userDao;
@Before
public void init() throws Exception {
in = Resources.getResourceAsStream("SqlMapConfig.xml");
factory = new SqlSessionFactoryBuilder().build(in);
sqlSession = factory.openSession();
userDao = sqlSession.getMapper(IUserDao.class);
}
@After
public void destory() throws Exception {
sqlSession.commit();
sqlSession.close();
in.close();
}
@Test
public void testFindAll(){
List users = userDao.findAll();
for (User user:users){
System.out.println(user);
}
}
@Test
public void testAddUser(){
User user = new User();
user.setUsername("wf");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("中國");
userDao.addUser(user);
}
@Test
public void testDeleteUser(){
userDao.deleteUser(49);
}
@Test
public void testUpdateUser(){
User user = new User();
user.setId(50);
user.setUsername("gx");
user.setBirthday(new Date());
user.setSex("女");
user.setAddress("中國");
userDao.updateUser(user);
}
@Test
public void testFindById(){
User user = userDao.findById(50);
System.out.println(user);
}
@Test
public void testFindByName(){
//List users = userDao.findByName("%王%");
List users = userDao.findByName("王");
for (User user:users){
System.out.println(user);
}
}
@Test
public void testFindTotal(){
int a = userDao.findTotal();
System.out.println(a);
}
}
3.4、mybatis基于注解的二級緩存
3.4.1、在SqlMapConfig中開啟二級緩存支持
3.4.2、在持久層接口中使用注解配置二級緩存
/**
*
*
Title: IUserDao
*
Description: 用戶的持久層接口
*/
@CacheNamespace(blocking=true)//mybatis 基于注解方式實現配置二級緩存
public interface IUserDao {}
總結
以上是生活随笔為你收集整理的java ssm框架 缓存_SSM框架之Mybatis(7)延迟加载、缓存及注解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大数据认知计算在内容安全管控中的应用
- 下一篇: web安全之点击劫持攻击(clickja