-------------------------------MyBatis-------------------------------
教程git倉庫源碼:[email protected]:can8888/Mybatis-study.git
1.簡介:
1.1什麼是Mybatis?
·Mybatis是一款優秀的持久層架構
·它支援定制化SQL、存儲過程以及進階映射。
·Mybatis避免了幾乎所有的JDBC代碼和手動設定參數以及獲得結果集。
·MyBatis可以使用簡單的XML或注解來配置和映射原生類型、接口和Java的POJO(Plain Old Java Objects,普通老式Java對象) 為資料庫中的記錄
·apache的一個開源項目IBatis,2010年這個項目由apache software foundation
遷移到了google code,并且改為MyBatis。
·2013年11月遷移到github
如何獲得Mybatis?
·maven倉庫
·github倉庫
1.2、持久化
資料持久化
·持久化就是将程式的資料在持久狀态(放到資料庫裡面,隻要不删除一直都在)和瞬時狀态轉化的過程
·記憶體:斷電即失
·資料庫(JDBC),io檔案持久化。
·生活:冷藏。罐頭
為什麼需要持久化?
·有一些對象,不能讓它丢掉。
·記憶體太貴了。
1.3、持久層
Dao層、Service層、Controller層…
·完成持久化工作的代碼塊
·層界限十分明顯。
1.4為什麼需要Mybatis?
·幫助程式員将資料存入到資料中。
·友善
·傳統的JDBC代碼太複雜。簡化。架構。自動化。
·不用Mybatis也可以。不過學了更容易上手
·優點:
·簡單易學
·靈活
·sql和代碼的分離,提高了可維護性
·提供映射标簽,支援對象與資料庫的orm字段關系映射
·提供對象關系映射标簽,支援對象關系組建維護
·提供了xml标簽,支援編寫動态sql。
最重要的一點:使用的人多!
2、第一個Mybatis程式
思路:搭建環境–>導入Mybatis–>編寫代碼–>測試!
2.1、搭建環境
搭建資料庫
create database
mybatis_can
; //建立資料庫
use ‘mybatis_can’; //使用資料庫
create table
user
(
id
int(10) not null primary key,
name
varchar(30) default null,
‘pwd’ varchar(30) default null
)engine=INNODB default charset=utf8; //建立表
insert into
user
(id,name,pwd)
values
(1,‘CAN’,‘123456’),
(2,‘張三’,‘123456’),
(3,‘李四’,‘123456’); //插入資料
建立項目
1.建立一個普通的maven項目
2.删除src
3.導入maven依賴
<dependencies>
<!--mysql驅動-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<!--Junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
2.2、建立一個子產品
1.編寫mybatis的核心配置檔案
<?xml version="1.0" encoding="UTF-8" ?>
<!--test環境-->
<environment id="test">
<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>
2.3、編寫代碼
1.實體類
```
package com.can.pojo;
//實體類
public class User {
private int id;
private String name;
private String pwd;
public User() {
}
public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
```
2.Dao接口
```
package com.can.dao;
import com.can.pojo.User;
import java.util.List;
public interface UserDao {
List<User> getUserList();
}
```
3.接口實作類由原來的JDBC方式UserDaoImpl實作類轉為Mapper配置檔案
```
<?xml version="1.0" encoding="UTF-8" ?>
select id,name,pwd from mybatis_can.user;
```
2.4、測試junit
注意點:
org.apache.ibatis.binding.BindingException: Type interface
com.can.dao.UserDao is not known to the MapperRegistry.
這個錯誤
類型接口,dao是未知的在mapper注冊裡
MapperRegistry是什麼?
核心配置檔案中注冊mappers
<mappers>
<mapper resource="com/can/dao/UserMapper.xml"></mapper>
</mappers>
可能遇到的問題:
1.配置檔案沒有注冊
2.綁定接口錯誤。
3.方法名不對。
4.傳回類型不對。
5.maven導出資源問題
3.CRUD
1、namespace
namespace中的包名要和Dao/mapper接口的包名一緻!
2、select
選擇,查詢語句
·id:就是對應的namespace中的方法名;
·resultType: Sql語句執行的傳回值!
·parameterType:參數類型!
3、insert
4、update
5、Delete
注意點增删改需要送出事務!
sqlSession.commit();
7.萬能的Map
Map傳遞參數,直接在SQL中取出key即可! 【parameterType=“map”】
對象傳遞參數,直接在sql中取對象的屬性即可! 【parameterType=“Object”】
隻有一個基本類型參數的情況下,可以直接在sql中取到 【可以不寫】
多個參數用Map!,或者注解
8、模糊查詢怎麼寫?
1.Java代碼執行的時候,傳遞通配符 %%
List userlist = userDao.getUserLike("%李%");
2.在sql拼接中使用通配符!
select * from mybatis_can.user where name like “%”#{value}"%"
4.配置解析!
1、核心配置檔案
·mybatis-config.xml
·MyBatis的配置檔案包含了會深深影響Mybatis行為的設定和屬性資訊。
configuration(配置)
properties(屬性)
settings(設定)
typeAliases(類型别名)
typeHandlers(類型處理器)
objectFactory(對象工廠)
plugins(插件)
environments(環境配置)
environment(環境變量)
transactionManager(事務管理器)
dataSource(資料源)
databaseIdProvider(資料庫廠商辨別)
mappers(映射器)
2、環境變量(environments)
Mybatis可以配置成适應多種環境
不過要記住:盡管可以配置多個環境,但每個SqlSessionFactory執行個體隻能選擇一種環境
transactionManager事務管理器 (JDBC|MANAGED(MAN基悶的))
如果是spring+Mybatis就完全沒必要配置這個
UNPOOLED|POOLED UNPOOLED(昂噗) 沒有池子| POOLED 有池子 池子:資料庫連接配接池 一個連完後不要關閉 等另外一個來連
學會使用配置多套運作環境!
Mybatis預設的事務管理器就是JDBC!,連接配接池:POOLED
3、屬性(properties)
我們可以通過properties屬性來實作引用配置檔案
這些屬性都是可外部配置且可動态替換的,既可以在典型的Java屬性檔案中配置,亦可通過properties元
素的子元素來傳遞。【db.properties】
編寫一個配置檔案 db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis_can?useSSL=true&;useUnicode=true&characterEncoding=UTF-8
username=root
password=root
在核心配置檔案中映入
<properties resource="db.properties">
<!-- 優先使用外部檔案(db.properties )-->
<property name="username" value="root"/>
<property name="password" value="root"/>
</properties>
·可以直接引入外部檔案
·可以在其中添加一些屬性配置
·如果兩個檔案有同一個字段,優先使用外部配置檔案的!
4、typeAliases(類型别名)
類型别名是為Java類型設定一個短的名字。
它隻和XML配置有關,存在的意義僅在于用來減少類完全限定名的備援。
<typeAliases>
<typeAlias type="com.can.pojo.User" alias="User"/>
</typeAliases>
也可以指定一個包名,Mybatis會在包名下面搜尋需要JavaBean,比如:
掃描實體類的包,它的預設的别名就為這個類的類名首字母小寫(大寫也可以 建議用小寫)
在實體類比較少的時候,使用第一種方式。
如果實體類十分多,建議使用第二種。
第一種可以DIY别名,第二種則不行,如果非要改,需要在實體類上增加注解 @Alias("_user")
5、設定(settings)
這是MyBatis中極為重要的調整設定,它們會改變Mybatis的運作時行為。
·cacheEnabled:全局地開啟或關閉配置檔案中的所有映射器已經配置的任何緩存。true|false Default:true。
·lazyLoadingEnabled:延遲加載的全局開關。當開啟時,所有關聯對象都會延遲加載。特定關聯關系中
可通過fetchType屬性來覆寫該項的開關狀态 true|false Default:false。
·logImpl 指定Mybatis所用日志的具體實作,未指定将自動查找。 SLF4J|LOG4J|LOG4J2|JDK_LOGGING
|COMMONS_LOGGING|STDOUT|LOGGING|NO_LOGGING Default:未設定
6、其他配置
·typeHandlers(類型處理器)
·objectFactory(對象工廠)
·plugins插件(基友搭配,效率翻倍)
·mybatis-generator-core
·mybatis-plus
·通用mapper
7、映射器(mappers)
MapperRegistry:注冊綁定我們的Mapper檔案;
方式一:
<mappers>
<mapper resource="com/can/dao/UserMapper.xml"></mapper>
</mappers>
使用相對于類路徑的資源引用
方式二:
<mappers>
<mapper class="com.can.dao.UserDao" />
</mappers>
方式二注意點:
·接口和它得Mapper配置檔案必須同名
·接口和它得Mapper配置檔案必須在同一包下! 或者在resource下建立跟java一樣的路徑
方式三:
<mappers>
<package name="com.can.dao" />
</mappers>
方式三使用掃描包進行注入綁定
方式三注意點:
·接口和它得Mapper配置檔案必須同名
·接口和它得Mapper配置檔案必須在同一包下! 或者在resource下建立跟java一樣的路徑
8.生命周期和作用域
生命周期,和作用域,是至關重要的,因為錯誤的使用會導緻非常嚴重的并發問題
SqlSessionFactoryBuilder: (Factory(fai可特瑞))
·一旦建立了SqlSessionFactory,就不在需要它了
·局部變量
SqlSessionFactory:
·說白了就是可以想象為:資料庫連接配接池
·SqlSessionFactory一旦被建立就應該在應用的運作期間一直存在,沒有任何理由丢棄它或重新創
建另一個執行個體。
·是以SqlSessionFactory的最佳作用域是應用作用域。
·最簡單的就是使用單例模式或靜态單例模式。
SqlSession:
·連接配接到連接配接池的一個請求!
·SqlSession的執行個體不是線程安全的,是以是不能被共享的,是以它的最佳作用域是請求或方法作用
域。
·用完之後需要趕緊關閉,否則資源被占用!
5、解決屬性名和字段名不一緻的問題
5.1、問題
類屬性字段是password,但是資料庫字段是pwd
類型處理器找不到pwd ,可以使用别名解決這個問題
解決方法:
·1.起别名
select id,name,pwd as password from mybatis_can.user where id=#{id}
5.2、resultMap
結果集映射
id name pwd
id name password
<!-- 結果集映射 --> <!-- 這裡的type="_user" 是實體類給了@Alias注解 -->
<resultMap id="UserMap" type="_user">
<!-- column資料庫中的字段,property實體類中的屬性 -->
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
<!-- resultMap 映射,解決屬性名和資料庫字段不一緻問題 -->
<select id="getUserById" parameterType="int" resultMap="UserMap">
select * from mybatis_can.user where id=#{id}
</select>
·resultMap 元素是MyBatis中最重要的最強大的元素
·ResultMap的設計思想是,對于簡單的語句根本不需要配置顯式的結果映射,而對于複雜一點的語句隻需
要描述它們的關系就行了。
·ResultMap 最優秀的地方在于,雖然你已經對它相當了解了,但是根本就不需要顯式地用到它們。
6、日志
6.1、日志工廠
如果一個資料庫操作,出現了異常,我們需要排錯,日志就是最好的助手!
曾經:sout、debug
現在:日志工廠
logImpl 指定Mybatis所用日志的具體實作,未指定将自動查找。
·SLF4J(賽咯否借)
·LOG4J·
·LOG4J2
·JDK_LOGGING(Java自帶的輸出包)
·COMMONS_LOGGING
·STDOUT_LOGGING(控制台輸出)
·NO_LOGGING(沒有日志輸出)
在MyBatis中具體使用那個一日志實作,在設定中設定!
STDOUT_LOGGING(控制台輸出)标準日志輸出
在mybatis核心配置檔案中,配置我們的日志!
Opening JDBC Connection
Created connection 802581203.
Setting autocommit to false on JDBC Connection [[email protected]]
==> Preparing: select * from mybatis_can.user where id=?
==> Parameters: 1(Integer)
<== Columns: id, name, pwd
<== Row: 1, CAN, 123456
<== Total: 1
User{id=1, name='CAN', password='123456'}
Resetting autocommit to true on JDBC Connection [[email protected]]
Closing JDBC Connection [[email protected]]
Returned connection 802581203 to pool.
Process finished with exit code 0
6.2、Log4j
什麼是Log4j?
·Log4j是Apache的一個開源項目,通過使用Log4j,我們可以控制日志資訊輸送的目的地是控制台,檔案、
GUI元件、甚至是套接口伺服器。
·我們可以控制每一條日志的輸出格式。
·通過定義每一條日志資訊的級别,我們能夠更加細緻地控制日志的生成過程。
·通過一個配置檔案來靈活地進行配置,而不需要修改應用的代碼。
1.先導入Log4j包
<!-- 導入Log4j -->
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2.log4j.properties
#将等級為DEBUG的日志資訊輸出到console的file這兩個目的地,console和file檔案的定義在下面代碼
log4j.rootLogger=DEBUG,console,file
#控制台輸出的相關設定
#控制的輸出使用log4j實作
log4j.appender.console = org.apache.log4j.ConsoleAppender
#日志使用Sout輸出
log4j.appender.console.Target = System.out
#DEBUG級别日志輸出
log4j.appender.console.Threshold = DEBUG
#日志輸出格式
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#檔案輸出的相關設定
log4j.appender.file = org.apache.log4j.RollingCalendar
##輸出位置
log4j.appender.file.File = ./log/Can.log
#檔案最大大小
log4j.appender.file.MaxFileSize = 10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
#輸出格式
log4j.appender.file.layout.ConversionPattern = [%p][%d{yy-MM-dd}][%c]%m%n
#日志輸出級别
# DEBUG意思是 DEBUG才會輸出
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
3.配置log4j為日志的實作
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
4.Log4j的使用,直接測試運作剛才的查詢
[org.apache.ibatis.logging.LogFactory]-Logging initialized using ‘class org.apache.ibatis.logging.log4j.Log4jImpl’ adapter.
[org.apache.ibatis.logging.LogFactory]-Logging initialized using ‘class org.apache.ibatis.logging.log4j.Log4jImpl’ adapter.
[org.apache.ibatis.io.VFS]-Class not found: org.jboss.vfs.VFS
[org.apache.ibatis.io.JBoss6VFS]-JBoss 6 VFS API is not available in this environment.
[org.apache.ibatis.io.VFS]-Class not found: org.jboss.vfs.VirtualFile
[org.apache.ibatis.io.VFS]-VFS implementation org.apache.ibatis.io.JBoss6VFS is not valid in this environment.
[org.apache.ibatis.io.VFS]-Using VFS adapter org.apache.ibatis.io.DefaultVFS
[org.apache.ibatis.io.DefaultVFS]-Find JAR URL: file:/D:/%e7%bb%83%e4%b9%a0%e9%a1%b9%e7%9b%aeidea(%e4%b8%8d%e5%8f%af%e5%88%a0)/%e7%bb%83%e4%b9%a0%e5%ad%a6%e4%b9%a0%e9%a1%b9%e7%9b%ae/Mybatis/mybatis-04/target/classes/com/can/pojo
[org.apache.ibatis.io.DefaultVFS]-Not a JAR: file:/D:/%e7%bb%83%e4%b9%a0%e9%a1%b9%e7%9b%aeidea(%e4%b8%8d%e5%8f%af%e5%88%a0)/%e7%bb%83%e4%b9%a0%e5%ad%a6%e4%b9%a0%e9%a1%b9%e7%9b%ae/Mybatis/mybatis-04/target/classes/com/can/pojo
[org.apache.ibatis.io.DefaultVFS]-Reader entry: User.class
[org.apache.ibatis.io.DefaultVFS]-Listing file:/D:/%e7%bb%83%e4%b9%a0%e9%a1%b9%e7%9b%aeidea(%e4%b8%8d%e5%8f%af%e5%88%a0)/%e7%bb%83%e4%b9%a0%e5%ad%a6%e4%b9%a0%e9%a1%b9%e7%9b%ae/Mybatis/mybatis-04/target/classes/com/can/pojo
[org.apache.ibatis.io.DefaultVFS]-Find JAR URL: file:/D:/%e7%bb%83%e4%b9%a0%e9%a1%b9%e7%9b%aeidea(%e4%b8%8d%e5%8f%af%e5%88%a0)/%e7%bb%83%e4%b9%a0%e5%ad%a6%e4%b9%a0%e9%a1%b9%e7%9b%ae/Mybatis/mybatis-04/target/classes/com/can/pojo/User.class
[org.apache.ibatis.io.DefaultVFS]-Not a JAR: file:/D:/%e7%bb%83%e4%b9%a0%e9%a1%b9%e7%9b%aeidea(%e4%b8%8d%e5%8f%af%e5%88%a0)/%e7%bb%83%e4%b9%a0%e5%ad%a6%e4%b9%a0%e9%a1%b9%e7%9b%ae/Mybatis/mybatis-04/target/classes/com/can/pojo/User.class
[org.apache.ibatis.io.DefaultVFS]-Reader entry: ���� 1 @
[org.apache.ibatis.io.ResolverUtil]-Checking to see if class com.can.pojo.User matches criteria [is assignable to Object]
[org.apache.ibatis.datasource.pooled.PooledDataSource]-PooledDataSource forcefully closed/removed all connections.
[org.apache.ibatis.datasource.pooled.PooledDataSource]-PooledDataSource forcefully closed/removed all connections.
[org.apache.ibatis.datasource.pooled.PooledDataSource]-PooledDataSource forcefully closed/removed all connections.
[org.apache.ibatis.datasource.pooled.PooledDataSource]-PooledDataSource forcefully closed/removed all connections.
[org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Opening JDBC Connection
[org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 1312884893.
[org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Setting autocommit to false on JDBC Connection [[email protected]]
[com.can.dao.UserMapper.getUserById]-> Preparing: select * from mybatis_can.user where id=?
[com.can.dao.UserMapper.getUserById]-> Parameters: 1(Integer)
[com.can.dao.UserMapper.getUserById]-<== Total: 1
User{id=1, name=‘CAN’, password=‘123456’}
[org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Resetting autocommit to true on JDBC Connection [[email protected]]
[org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [[email protected]]
[org.apache.ibatis.datasource.pooled.PooledDataSource]-Returned connection 1312884893 to pool.
Process finished with exit code 0
簡單使用
1.
在要使用的Log4j的類中,導入包import org.apache.log4j.Logger;
2.
日志對象,參數為目前類的class
private static Logger logger = Logger.getLogger(UserDaoTest.class);
3.
日志級别
logger.info("info:進入了testLog4j方法"); logger.debug("debug:進入了testLog4j方法"); logger.error("error:進入了testLog4j方法");
7、分頁
思考:為什麼要分頁?
·減少資料的處理量
7.1、使用Limit分頁
文法:select * from user limit startIndex,pageSize;
如果隻給一個參數 那麼startIndex預設為0
文法:select * from user limit 6; #[0,6]
使用Mybatis實作分頁,核心SQL
1.接口
//分頁
List<User> getUserByLimit(Map<String,Object> map);
2.Mapper.xml
<!-- 分頁 -->
<select id="getUserByLimit" parameterType="map" resultType="user">
select * from mybatis_can.user limit #{startIndex},#{pageSize};
</select>
3.測試
@Test
public void getUserByLimit(){
try {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
Map<String,Object> map = new HashMap<String,Object>();
map.put("startIndex",2);
map.put("pageSize",2);
List<User> userList = userMapper.getUserByLimit(map);
for (User user:userList){
System.out.println(user);
}
}finally {
sqlSession.close();
}
}
7.2、RowBounds分頁
不再使用SQL實作分頁
1.接口
//RowBounds分頁2
List<User> getUserByRowBounds();
2.mapper.xml
<!-- 分頁2:RowBounds -->
<select id="getUserByRowBounds" resultMap="UserMap">
select * from mybatis_can.user;
</select>
3.測試
@Test
public void getUserByRowBounds(){
try {
//RowBounds實作,參數跟Limit一樣的道理
RowBounds rowBounds = new RowBounds(0,1);
//通過Java代碼層面實作分頁 (注意有三個參數,第三個參數才是RowBounds)
List<User> users = sqlSession.selectList("com.can.dao.UserMapper.getUserByRowBounds",null,rowBounds);
for (User user : users) {
System.out.println(user);
}
}finally {
sqlSession.close();
}
}
前端也可以實作分頁
7.3、分頁插件
·MyBatis分頁插件PageHelper
8、使用注解開發
1.注解在接口上實作
@Select("select * from user") List<User> getUsers();
2.需要再核心配置檔案中綁定接口!
<!-- 綁定接口 --> <mappers> <mapper class="dao.UserMapper"/> </mappers>
3.測試
本質:反射機制實作
底層:動态代理!
MyBatis詳細的執行流程
1.Resources擷取加載全局配置檔案
2.執行個體化SqlSessionFactoryBuilder構造器
3.解析檔案流XMLConfigBuilder
4.傳回給 Conifguraction(Config睿性)所有的配置資訊
5.SqlSessionFactory執行個體化
6.建立transactional(川辣西No)事務管理器
7.建立executor(一次Q特)執行器
8.建立sqlSession
9.實作CRUD crud
10.檢視是否執行成功
11.送出事務
12.關閉
8.3、CRUD
我們可以在工具類建立的時候實作自動送出事務!
public static SqlSession getSqlSessionTranIsTrue(){
return sqlSessionFactory.openSession(true);
}
編寫接口,增加注解
public interface UserMapper {
@Select("select * from user")
List<User> getUsers();
//方法存在多個參數,所有的參數前面必須加上@Param
//@Param("id")要對應SQL裡的參數#{id}
@Select("select * from user where id=#{id}")
User getUserById(@Param("id") int idddd);
@Insert("insert into user (id,name,pwd) values(#{id},#{name},#{password})")
int addUser(User user);
@Update("update user set name=#{name},pwd=#{password} where id=#{id}")
int updateUser(User user);
@Delete("delete from user where id=#{uid}")
int deleteUser(@Param("uid") int id);
}
測試類
【注意點:我們必須要将接口注冊綁定到我們的核心配置中!】
<!-- 綁定接口 -->
<mappers>
<mapper class="dao.UserMapper"/>
</mappers>
關于@Parame()注解
·基本類型的參數或者String類型,需要加上
·引用類型不需要加
·如果隻有一個基本類型的話,可以忽略,但是建議大家都加上!
·我們在SQL中引用的就是我們這裡的@Parme(“uid”)中設定的屬性名!
#{}、${}差別
${}不安全
#{}防止SQL注入
9、Lombok(Null伯克)
·java library(java的庫)
·plugs(插件)
·build tools(建構工具)
·with one annotation your class (用一個注釋你的類)
使用步驟:
1.在IDEA中安裝Lombok插件!
2.在項目中導入Lombok包
<!-- Lombok依賴-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
@Getter and @Setter
@FieldNameConstants //字段屬性常量
@ToString
@EqualsAndHashCode
@AllArgsConstructor, //全部的構造參數
@RequiredArgsConstructor
and
@NoArgsConstructor //無參構造
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors //鍊式操作
@Wither
@With
@SneakyThrows
@Data:無參構造,get,set,toString,hashcode,equals
@AllArgsConstructor:有參構造
@NoArgsConstructor:無參構造
@[email protected] 可以單獨給字段使用,也可以在實體類上用
@NonNull:用在方法前,會自動對該參數進行非空檢驗,為空抛出NPE(NullPointerException)
@Cleanup:自動管理資源,用在局部變量之前,在目前變量範圍即将執行完畢退出前會清理資源,生成
try-finally的代碼關閉流
@ToString:用在類上,可以自動覆寫toString方法
@EqualsAndHashCode:用在類上,自動生成equals方法和hashCode方法
@Value:用在類上,是@Data的不可變形式,相當于為屬性添加final聲明,隻提供getter方法,而不提
供setter方法
@SneakyThrows:自動抛出受檢異常,而不需顯式在方法上使用throws語句
@Synchronized:用在方法上,将方法聲明為同步的,并自動加鎖
Lombok的優缺點:
優點:
1.能通過注解的形式自動生成構造器、getter等方法,提高了一定的開發效率
2.讓代碼變得更簡潔,不用過多的去關注相應的方法
3.屬性做修改時,也簡化了維護為這些屬性所生成的getter/setter方法等
缺點:
1.不支援多種參數構造器的重載,但是可以自己手動添加
2.雖然省去了手動建立getter/setter方法的麻煩,但大幅度降低了源代碼的可讀性和完整性,降低了
閱讀源代碼了舒适度
10、多對一處理
多對一:
·多個學生對應一個老師
·對于學生這邊而言,關聯… 多個學生關聯一個老師【多對一】
·對于老師而言,集合,一個老師有很多學生【一對多】
SQL:
create TABLE `teacher` (
id int(10) NOT NULL,
name varchar(30) default null,
primary key (`id`)
)ENGINE=INNODB default charset=utf8;
insert into teacher (id, name) values (1,'謝老師');
create table `student` (
`id` int(10) not null,
`name` varchar(30) default null,
`tid` int(10) default null,
primary key(`id`),
key `fktid` (`tid`),
constraint `fktid` foreign key (`tid`) references `teacher` (`id`)
)ENGINE=INNODB default charset=utf8;
insert into `student` values ('1','小明','1');
insert into `student` values ('2','小紅','1');
insert into `student` values ('3','小綠','1');
insert into `student` values ('4','小花','1');
insert into `student` values ('5','小天','1');
測試環境搭建
1.導入Lombok
2.建立實體類Teacher,Student
3.建立Mapper接口
4.建立Mapper.xml檔案
5.在核心配置檔案中,綁定注冊我們的Mapper接口或者檔案!【方式很多,随心選】
6.測試查詢是否能夠成功!
按照查詢嵌套處理
<!--
思路:
1.查詢所有的學生資訊
2.根據查詢出來的學生的tid,尋找對應的老師! 子查詢
-->
<resultMap id="studentTeacher" type="student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<!-- 複雜的屬性,我們需要單獨處理 對象:association 集合:collection -->
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
<!-- <collection property=""/>-->
</resultMap>
<select id="getStudent" resultMap="studentTeacher">
select s.id,s.name,s.tid,t.name from student s,teacher t where s.tid=t.id;
</select>
<select id="getTeacher" resultType="teacher">
select * from teacher where id= #{id};
</select>
按照結果嵌套查詢
<!-- 方法二 按照結果處理嵌套處理 -->
<resultMap id="getStudent2" type="student">
<result property="id" column="sid" />
<result property="name" column="sname" />
<association property="teacher" javaType="Teacher" >
<result property="id" column="tid"/>
<result property="name" column="tname"/>
</association>
</resultMap>
<select id="getStudent2" resultMap="getStudent2">
select s.id sid,
s.name sname,
t.id tid,
t.name tname
from student s,teacher t
where s.tid=t.id;
</select>
11、一對多處理
比如:一個老師擁有多個學生!
對于老師而言,就是一對多的關系!
1.環境搭建,和剛才一樣
2.實體類
@Data
public class Student {
private int id;
private String name;
private int tid;
}
@Data
public class Teacher {
private int id;
private String name;
//一個老師擁有多個學生
private List<Student> student;
}
按照結果嵌套處理
<!-- 按結果嵌套查詢-->
<select id="getTeacher" resultMap="TeacherStudent">
select s.id sid,
s.name sname,
t.name tname,
t.id tid
from student s,teacher t
where s.tid =t.id
and t.id=#{tid};
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<!-- 複雜的屬性,我們需要單獨處理 對象: association 集合: collection
javaType="" 指定屬性的類型
集合中的泛型資訊,我們使用ofType擷取,不能用javaType 這裡可以不加 javaType="ArrayList-->
<collection property="student" ofType="Student" javaType="ArrayList">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
按照查詢嵌套處理
<!-- 子查詢方式實作 -->
<select id="getTeacher2" resultMap="TeacherStudent2">
select * from teacher where id=#{tid};
</select>
<resultMap id="TeacherStudent2" type="Teacher">
<result property="id" column="id"/>
<collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTid" column="id"/>
</resultMap>
<select id="getStudentByTid" resultType="Student">
select * from student where tid =#{tid};
</select>
小結:
1.關聯-association(偶首撕A型) 【多對一】
2.集合-collection 【一對多】
3.javaType & ofType
1.JavaType 用來指定實體類中的屬性類型
2.ofType 用來指定映射到List或者集合中的pojo類型,泛型中的限制類型
注意點:
·保證SQL的可讀性,盡量保證通俗易懂。
·注意一對多和多對一,屬性名和字段的問題!
·如果問題不好排查錯誤,可以使用日志,建議使用Log4j
面試高頻
·Mysql引擎
·InnoDB底層原理
·索引
·索引優化
12、動态SQL
什麼是動态SQL:動态SQL就是指根據不同的條件生成不同的SQL語句
利用動态SQL這一特性可以徹底擺脫這種痛苦
動态SQL元素和JSTL或基于類似XML的文本處理器相似?。在MyBatis之前的版本中,有很多元素需要花
時間了解。MyBatis3大大簡化了元素種類,現在隻需學習原來一半的元素便可。MyBatis 采用功能強大
基于OGNL的表達式淘汰其他大部分元素。
if
choose(when,oherwise)
trim(where,set)
foreach
搭建環境
SQL
create table `blog` (
`id` varchar(50) NOT NULL COMMENT '部落格Id',
`title` varchar(100) NOT NULL COMMENT '部落格标題',
`author` varchar(30) NOT NULL COMMENT '部落格作者',
`create_time` DATETIME not null COMMENT '建立時間',
`views` int(30) NOT NULL COMMENT '浏覽量'
)ENGINE=INNODB DEFAULT CHARSET=UTF8;
insert into `blog` (id,title,author,create_time,views) values
(REPLACE(UUID(),'-',''),'MyBatis如此簡單','CAN',NOW(),5000),
(REPLACE(UUID(),'-',''),'Java如此簡單','CAN',NOW(),1000),
(REPLACE(UUID(),'-',''),'Spring如此簡單','CAN',NOW(),9999),
(REPLACE(UUID(),'-',''),'微服務如此簡單','CAN',NOW(),9999);
建立一個基礎工程
1.導包
2.編寫配置檔案
@Data public class Blog { private String id; private String title; private String author; private Date createTime; private int views; }
3.編寫實體類
4.編寫實體類對應的Mapper接口 和 Mapper.XML檔案
·IF
<mapper namespace="com.can.dao.BlogMapper">
<select id="queryBlogIF" resultType="blog" parameterType="map">
select * from blog where 1=1
<if test="title !=null">
and title like "%"#{title}"%"
</if>
<if test="author !=null">
and author = #{author}
</if>
</select>
</mapper>
choose(when,otherwise)
<!-- Choose -->
<select id="queryBlogChoose" resultType="blog" parameterType="map">
select * from blog
<where>
<choose>
<when test="title !=null">
title like "%"#{title}"%"
</when>
<when test="author !=null">
author = #{author}
</when>
<otherwise>
views = #{views}
</otherwise>
</choose>
</where>
</select>
trim(where,set)
<!-- IF where -->
<select id="queryBlogIF" resultType="blog" parameterType="map">
select * from blog
<where>
<if test="title !=null">
and title like "%"#{title}"%"
</if>
<if test="author !=null">
and author = #{author}
</if>
</where>
</select>
<!-- set -->
<update id="updateBlog" parameterType="map">
update Blog
<set>
<if test="title !=null">
title = #{title},
</if>
<if test="author !=null">
author = #{author},
</if>
</set>
<where>
id = #{id}
</where>
</update>
<!-- trim自定義 -->
<trim prefix="WHERE" prefixOverrides="AND |OR" suffix="" suffixOverrides="">
</trim>
<select id="queryBlogTrim" parameterType="map" resultType="Blog">
select * from blog
<trim prefix="WHERE 1=1 AND" prefixOverrides="AND" suffix="and 2=2" suffixOverrides=",">
<if test="title !=null">
and title = #{title}
</if>
<if test="author !=null">
and author = #{author},
</if>
</trim>
<!-- SQL列印 : select * from blog WHERE 1=1 AND title = ? and author = ? and 2=2 -->
where标簽 如果有條件元素傳回 就拼接where 如果條件第一個是and或者or就自動删除and或or。
set标簽 會動态前置set關鍵字,同時會自動删除無關的逗号。
trim标簽 就是可以自定義
(prefixOverrides屬性會忽略通過管道分隔的文本序列(注意此列中的空也是必要的)),
它的作用是移除所有指定在prefixOverrides屬性中的内容,并且插入prefix屬性中的指定的内容。
suffixOverrides指定字尾替換成suffix
字首字尾是指的trim一整塊SQL,而不是IF标簽裡的前字尾
Foreach
<!-- foreach
collection:對應傳參Map的Key
collection從這裡的每一項集合周遊成item
open:字首
separator:每個周遊字尾 分隔符
close:字尾
index:周遊的下标(從0開始) -->
<select id="queryBlogForeach" resultType="Blog" parameterType="map">
select * from blog
<where>
<if test="ids !=null and ids.size()>0">
id IN
<foreach collection="ids" item="item" open=" (" separator="," close=")" index="index">
#{item}
</foreach>
</if>
</where>
</select>
SQL片段
有的時候,我們可能會将一些功能的部分抽取出來,友善複用!
1.使用SQL标簽抽取公共部分
<!-- SQL片段 --> <sql id="if-title-author"> <if test="title !=null"> title like "%"#{title}"%" </if> <if test="author !=null"> and author = #{author} </if> </sql>
2.在需要使用的地方使用include标簽引用即可
<select id="queryBlogIF" resultType="blog" parameterType="map">
select * from blog
<where>
<include refid="if-title-author"></include>
<!-- <if test="title !=null">
and title like "%"#{title}"%"
</if>
<if test="author !=null">
and author = #{author}
</if>-->
</where>
</select>
include标簽引用SQL片段。
注意事項::
最好基于單表來定義SQL片段!
·不要存在where标簽
所謂的動态SQL,本質還是SQL語句,隻是我們可以SQL層面,去執行一些邏輯代碼
動态SQL就是在拼接SQL語句,我們隻要保證SQL的正确性,按照SQL的格式,去排列組合就可以了
13.1、緩存
1.什麼是緩存[Cache]?
·存在記憶體中的臨時資料。
·将使用者經常查詢的資料存放在緩存(記憶體)中,使用者去查詢資料就不用從磁盤上(關系型資料庫
資料檔案)查詢,從緩存中查詢,進而提高查詢效率,解決了高并發系統的性能問題。
2.為什麼使用緩存?
·減少和資料庫的互動次數,減少系統開銷,提高系統效率。
3.什麼樣的資料能使用緩存?
·經常查詢并且不經常改變的資料。【可以使用緩存】
不經常查詢或經常改變的資料【不能使用緩存】
查詢 :連接配接資料庫,耗資源!
一次查詢的結果,給它暫存到一個可以直接取到的地方 -->記憶體:緩存
我們再次查詢相同資料的時候,直接走緩存,就不用走資料庫了
13.2、Mybatis緩存
·MyBatis包含一個非常強大的查詢緩存特性,它可以非常友善地定制和配置緩存。緩存可以極大的
提升查詢效率。
·MyBatis系統中預設定義了兩級緩存:一級緩存和二級緩存
·預設情況下,隻有一級緩存開啟。(SqlSession級别的緩存,也成為本地緩存)
·二級緩存需要手動開啟和配置,它是基于namespace級别的緩存。
·為了提高擴充性,MyBatis定義了緩存接口Cache。我們可以通過實作Cache接口來自定義二級緩存
13.3、一級緩存
一級緩存 在建立Sqlsession到close結束之間有效
·一級緩存也叫本地緩存:SqlSession
·與資料庫同一次會話期間查詢到的資料會放在本地緩存中。
·以後如果需要擷取相同的資料,直接從緩存中拿,沒必要再去查詢資料庫。
測試步驟:
1.開啟日志!
2.測試在一個Session中查詢兩次相同記錄
3.檢視日志輸出
Opening JDBC Connection
Created connection 1545087375.
==> Preparing: select * from user WHERE id = ?
==> Parameters: 1(Integer)
<== Columns: id, name, pwd
<== Row: 1, CAN, 123456
<== Total: 1
User(id=1, name=CAN, pwd=123456)
=============================================================
User(id=1, name=CAN, pwd=123456)
true
Closing JDBC Connection [[email protected]]
Returned connection 1545087375 to pool.
緩存失效的情況:執行了修改操作
Opening JDBC Connection
Created connection 1434041222.
==> Preparing: select * from user WHERE id = ?
==> Parameters: 1(Integer)
<== Columns: id, name, pwd
<== Row: 1, CAN, 123456
<== Total: 1
User(id=1, name=CAN, pwd=123456)
==> Preparing: update user SET name = ?, pwd = ? WHERE id = ?
==> Parameters: Java真好(String), 密碼123456(String), 2(Integer)
<== Updates: 1
=============================================================
==> Preparing: select * from user WHERE id = ?
==> Parameters: 1(Integer)
<== Columns: id, name, pwd
<== Row: 1, CAN, 123456
<== Total: 1
User(id=1, name=CAN, pwd=123456)
false
Closing JDBC Connection [[email protected]]
Returned connection 1434041222 to pool.
1.查詢不同的東西
2.增删改操作,可能會改變原來的資料,是以必定會重新整理緩存!
3.查詢不同的Mapper.xml
4.手動清理緩存!【sqlSession.clearCache(); //手動清理緩存】
小結:一級緩存預設是開啟的,隻在一次SqlSession中有效,也就是拿到連接配接到關閉連接配接這個區間段!
一級緩存就是于一個Map,用的時候取
SqlSession的連接配接到關閉的這個區間段與資料庫的同一次會話查詢到的資料會存入緩存中
如果執行了不同的查詢或者是執行了增删改操作或手動清理了緩存,就會重新整理緩存。
13.4、二級緩存
預設情況下,隻啟用了本地的會話緩存,它僅僅是一個會話中的資料進行緩存。要啟用全局二級緩存
,隻需要在你的SQL映射檔案中添加一行: //還要開啟全局緩存
基本上就是這樣。這個簡單語句的效果如下:
·映射語句檔案中的所有select語句的結果将會被緩存。
·映射語句檔案中的所有inset,update和delete語句會重新整理緩存
·緩存會使用最近最少使用算法(LRU,Least Recently Used)算法來清除不需要的緩存。
·緩存不會定時進行重新整理(也就是說,沒有重新整理間隔)
·緩存會儲存清單或對象(無論查詢方法傳回哪種)的1024個引用。
·緩存會被視為讀/寫緩存,這意味着擷取到的對象并不是共享的,可以安全地調用者修改,而不幹擾
其他調用者或線程所做的潛在修改。
提示:緩存隻作用于cache标簽所在的映射檔案中的語句。如果你混合使用Java API和XML 映射檔案,
在共用接口中的語句将不會被預設緩存。你需要使用@CacheNamespaceRef注解指定緩存作用域
這些屬性可以通過cache元素的屬性來修改。比如:
這個更進階的配置建立了一個FIFO緩存,每隔60秒重新整理,最多可以存儲結果對象或清單512引用 而且傳回
的對象被認為是隻讀的,是以對他們進行修改可能會在不同線程中的調用者産生沖突。
可用的清除政策有:
·LRU-最近最少使用:移除最長時間不被使用的對象。
·FIFO-先進先出:按對象進入緩存的順序來移除它們。
·SOFT-軟引用:基于垃圾回收器狀态和軟引用規則移除對象。
·WEAK-弱引用:更積極地基于垃圾收集器狀态和弱引用規則移除對象。
·二級緩存也叫全局緩存,一級緩存作用域太低了,是以誕生了二級緩存。
·基于namespace級别的緩存,一個名稱空間,對應一個二級緩存。
·工作機制:
·一個會話查詢一條資料,這個資料就會被放在目前會話的一級緩存中。
·如果目前會話關閉了,這個會話對應的一級緩存就沒了。但是我們想要的是,會話關閉了,一級緩存
中的資料被儲存到二級緩存中。
·新的會話查詢資訊,就可以從二級緩存中擷取内容。
·不同的mapper查出的資料會放在自己對應的緩存(map)中
步驟:
1.開啟全局緩存.雖然預設是開啟的,但一般還是顯式的把它寫出來.
<settings> <!-- 顯式的開啟全局緩存(二級緩存) --> <setting name="cacheEnabled" value="true"/> </settings>
2.在要使用二級緩存的Mapper.xml開啟二級緩存
```
<cache />
```
也可以自定義參數
```
<!-- 在目前Mapper.xml中使用二級緩存
·LRU-最近最少使用:移除最長時間不被使用的對象。
·FIFO-先進先出:按對象進入緩存的順序來移除它們。
·SOFT-軟引用:基于垃圾回收器狀态和軟引用規則移除對象。
·WEAK-弱引用:更積極地基于垃圾收集器狀态和弱引用規則移除對象。
eviction:使用的清除政策 flushInterval:每隔多少秒重新整理緩存(1000=1秒) size:最多隻能存多少緩存 readOnly:是否隻讀 -->
<cache eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
```
3.測試
//測試代碼
@Test
public void queryCache(){
SqlSession sqlSession = MybatisUtils.getSqlSessionTranIsTrue();
SqlSession sqlSession2 = MybatisUtils.getSqlSessionTranIsTrue();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.queryUserById(1);
User user3 = userMapper.queryUserById(2);
System.out.println(user);
sqlSession.close(); //close後會把一級緩存丢到二級緩存裡(二級緩存隻針對同一個namespace有效)
System.out.println("=============================================================");
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
User user2 = userMapper2.queryUserById(1);
System.out.println(user2);
System.out.println(user2==user);
sqlSession2.close();
}
代碼日志列印
Cache Hit Ratio [com.can.dao.UserMapper]: 0.0
Opening JDBC Connection
Created connection 1758386724.
==> Preparing: select * from user WHERE id = ?
==> Parameters: 1(Integer)
<== Columns: id, name, pwd
<== Row: 1, CAN, 123456
<== Total: 1
Cache Hit Ratio [com.can.dao.UserMapper]: 0.0
==> Preparing: select * from user WHERE id = ?
==> Parameters: 2(Integer)
<== Columns: id, name, pwd
<== Row: 2, Java真好, 密碼123456
<== Total: 1
User(id=1, name=CAN, pwd=123456)
Closing JDBC Connection [[email protected]]
Returned connection 1758386724 to pool.
=============================================================
Cache Hit Ratio [com.can.dao.UserMapper]: 0.3333333333333333
User(id=1, name=CAN, pwd=123456)
true
在sqlSession.close();關閉後就把一級緩存放到了二級緩存中,是以User user2 = userMapper2.queryUserById(1);
就直接從緩存中取到的資料,沒有執行資料庫查詢,Cache Hit Ratio從緩存中取,日志中也隻列印了兩個查詢
1.問題:我們需要将實體類序列化!否則就會報錯!(隻讀沒事) implements Serializable
小結:
·隻要開啟了二級緩存,在同一個Mapper.xml下就有效
·所有的資料都會先放在一級緩存中;
·隻有當會話送出,或者關閉的時候,才會送出到二級緩存中!
·查詢語句的元素屬性 useCache=“false” 可以讓這條查詢 不使用緩存。
·增删改操作的元素屬性flushCache=“false” 可以讓增删改後不重新整理緩存,調優的時候可以使用,提高查詢效率
13.5、緩存原理
·緩存順序:
1.先看二級緩存中有沒有
2.再看一級緩存中有沒有
3.查詢資料庫
13.6、自定義第三方緩存-ehcache(eh咔氣)
Ehcache是一種廣泛使用的開源Java分布式緩存。主要面向通用緩存
要在程式中使用ehcache,要先導包
<!-- ehcache -->
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.1.0</version>
</dependency>
在Mapper.xml中指定使用ehcache緩存實作!
<!-- 使用第三方緩存
type:使用pom引入的maven第三方緩存EhCache
type屬性指定的類必須實作org.mybatis.cache.Cache接口,且提供y一個接收String參數作為id的構造器 -->
<cache type="org.mybatis.caches.ehcache.EhcacheCache" />
resouces下建立ehcache.xml檔案
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http:/ehcache.org/ehcache.xsd"
updateCheck="false">
<!-- diskStore: 為緩存路徑, ehcache分為記憶體和磁盤兩級,此屬性定義磁盤的緩存位置。
參數解釋如下:
user.home-使用者主月錄
user.dir-使用者目前工作日錄
java. io.tmpdir -預設臨時檔案路徑
-->
<diskStore path="./tmpdir/Tmp_EhCache"/>
<defaultCache
eternal="false"
maxElementsInMemory="10000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="259200"
memoryStoreEvictionPolicy="LRU"/>
<cache
name="cloud_user"
eternal="false"
maxElementsInMemory="5000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
memoryStoreEvictionPolicy="LRU"/>
<!--
defaultCache:預設緩存政策, 當ehcache找不到定義的緩存時,則使用這個緩存政策。隻能定義一個。
-->
<!--
name:緩存名稱。
maxELementsInMemory:緩存最大數目
maxELementsOnDisk:硬碟最大緩存個數。
eternal:對象是否永久有效,一但設定了, timeout将不起作用。(就是儲存到硬碟)
overfLowToDisk:是否儲存到磁盤,當系統當機時
timeToIdleSeconds:設定對象在失效前的允許閑置時間(機關:秒)。僅當eternal=false對象不是永久有效時使用,可選屬性, 預設值是e,也就是
timeToliveSeconds:設定對象在失效前允許存活時間(機關:秒)。最大時間介于建立時間和失效時間之間。僅當eternal=false對象不是永久有效時
diskPersistent:是否緩存虛拟機重新開機期資料Whether the disk store persists between restarts of the Virtual Machine. The default
diskSpooLBufferSizeMB:這個參數設定DiskStore (磁盤緩存)的緩存區大小。預設是30MB。每個Cache都應該有自己的一個緩沖區。
diskExpiryThreadIntervalSeconds:磁盤失效線程運作時間間隔,預設是120秒。
memoryStoreEvictionPolicy:當達到maxELementsInMemory 限制時,Ehcache 将會根據指定的政策去清理記憶體。預設政策是LRU (最近最少使用)。
clearOnFLush:記憶體數量最大時是否清除。
memoryStoreEvictionPolicy:可選政策有: LRU (最近最少使用,預設政策)、FIFO (先團先出)、LFU (最少通路次數)。
-->
</ehcache>
是引用緩存
現在一般緩存都會使用Redis資料庫來做緩存!