MyBatis简单学习
MyBatis
MyBatis是优秀的持久层框架,持久层
持久化就是将程序的数据在持久状态和瞬时状态的转化的过程。而内存有断电即失的特性,为了数据不丢失,需要持久化数据,而且内存也很珍贵。
持久层:Dao层,Service层,Controller层。。。完成持久化的代码块,其层界限明显。
MyBatis是为了方便JDBC,方便数据存储,方便后续优化。将sql语句独立出来。
3.5.6版本MyBatis的Maven依赖:
1 | <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> |
第一个MyBatis程序
项目环境搭建省略。
官网:https://mybatis.org/mybatis-3/zh/index.html
基本配置(Mapper配置不要忘)
核心xml配置文件(文件路径用/而不是.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="111111"/>
</dataSource>
</environment>
</environments>
<!-- 每个Mapper.xml文件都需要在核心配置中注册配置 -->
<mappers>
<mapper resource="com/tang/dao/UserMapper.xml"/>
</mappers>
</configuration>工具类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public class MyBatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
//获得SqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
代码
实体类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48public class User {
private int id;
private String username;
private String password;
public User() {
}
public User(int id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}Dao接口
1
2
3public interface UserDao {
List<User> getUserList();
}接口实现(mapper.xml)
1
2
3
4
5
6
7
8
9
10
11
<!--绑定Mapper/Dao接口-->
<mapper namespace="com.tang.dao.UserDao">
<!-- 查询语句 -->
<select id="getUserList" resultType="com.tang.pojo.User">
select * from mybatis.user
</select>
</mapper>
测试(约定大于配置!)
The error may exist in com.tang.dao/UserMapper.xml
Maven约定大于配置,要配置识别文件的代码在pom里
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
junit测试
1
2
3
4
5
6
7
8
9
10
11
12public class UserDaoTest {
public void test(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> userList = userDao.getUserList();
for(User user : userList){
System.out.println(user);
}
sqlSession.close();
}
}
注意点
- mybatis的配置文件中,要为每一个mapper声明,也就是每个sql语句文件都要声明
- 当我们Mapper.xml书写不规范,例如写在资源文件夹以外的文件夹中,由于Maven约定大于配置,它不会编译其他文件夹中的xml,这时我们要去pom.xml中声明相关resource,最好父子项目均声明
CURD(mapper.xml)
语句基本配置
namespace应和dao目录下mapper文件一致
id:使用namespace中的方法
resultType(select独占sqlSession.close();):使用id对应方法的返回值(工具类封装好了get、set)
parameterType:方法的参数类型
注意!增删改一定要提交事务:sqlSession.commit()
步骤
编写接口类(注意增删改的返回类型,它会返回被影响数据的个数,所以是int型)
1
2
3
4
5
6
7
8
9
10
11
12
13
14public interface UserMapper {
/**查询所有用户,返回用户列表*/
List<User> getUserList();
/**ID查询用户*/
User getUserById(int id);
/**insert会返回查询行数,故设为int型*/
int addUser(User user);
int updateUser(User user);
int deleteUser(int id);
}在mapper文件中编写对应的sql语句
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22<mapper namespace="com.tang.dao.UserMapper">
<select id="getUserList" resultType="com.tang.pojo.User">
select * from mybatis.user;
</select>
<select id="getUserById" parameterType="int" resultType="com.tang.pojo.User">
select * from mybatis.user where id = #{id}
</select>
<insert id="addUser" parameterType="com.tang.pojo.User">
insert into mybatis.user (id,username,password) values (#{id},#{username},#{password});
</insert>
<update id="updateUser" parameterType="com.tang.pojo.User">
update mybatis.user set username = #{username},password = #{password} where id = #{id}
</update>
<delete id="deleteUser" parameterType="int">
delete from mybatis.user where id = #{id}
</delete>
</mapper>测试(注意一定增删改要提交事务)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57public class UserDaoTest {
public void test(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserList();
for(User user : userList){
System.out.println(user);
}
sqlSession.close();
}
public void getUserById(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.getUserById(1);
System.out.println(user);
sqlSession.close();
}
//增删改要提交事务
public void addUser(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.addUser(new User(4,"她她她","444"));
sqlSession.commit();
sqlSession.close();
}
public void updateUser(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.updateUser(new User(4,"地导弹","555"));
sqlSession.commit();
sqlSession.close();
}
public void deleteUser(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.deleteUser(4);
sqlSession.commit();
sqlSession.close();
}
}
使用Map
使用map操作参数,可自行操作变量,不用按数据库规定
1 | <!-- 使用map,可自定义变量名 --> |
测试时,map直接放入键值对,对应mapper的配置就行,这就不用受数据库的限制
1 |
|
模糊查询
1 | <select id="getUserLike" resultType="com.tang.pojo.User"> |
必须要在传递数据的添加调配符%,因为一个%就指代其他任意字符,我们这就相当于拼接字符串,举个例子就是X王X,2、3个字中带有王就可以查出,但Oracle数据库中就不能这样写。一般通配符写在mapper配置文件中就行,就不在java执行时写通配符,执行时传val的值即可
参考:https://blog.csdn.net/zhenwei1994/article/details/81876278
配置解析
核心配置文件
官网:https://mybatis.org/mybatis-3/zh/configuration.html#
1 | configuration(配置) |
环境配置(environments)
环境可配置多个,但每次只能选择一个使用
1 | <environments default="development"> |
transactionManager:JDBC | MANAGED
dataSource:dbcp、c3p0等等,连接数据库的
MyBatis默认事务管理器是JDBC,连接池是POOLED(池的概念)
属性(properties)
可通过properties属性来被其他配置文件引用
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。(db.properties)
db.properties(外部配置文件)
1 | driver=com.mysql.jdbc.Driver |
在核心配置文件中引用
1 | <properties resource="db.properties"/> |
我们也可以在properties标签中添加一些属性配置,但同名配置外部配置文件优先。
设置(settings)
重要的调整设置,看官网吧,太多了。
设置名 | 描述 | 有效值 | 默认值 |
---|---|---|---|
cacheEnabled | 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 | true | false | true |
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 |
true | false | false |
logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | 未设置 |
类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
法一:可直接给实体类起别名
1 | <typeAliases> |
法二:也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,即定义实体类在的包,然后在Mapper中使用Java Bean时可直接使用其首字母小写形式作为别名
1 | <typeAliases> |
- 实体类较少建议使用1,多的时候用2
- 法一可直接自定义别名,法二也可通过注解自定义别名
特殊别名
基本类型和一些数据结构有特殊的别名
别名 | 映射的类型 |
---|---|
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
object | Object |
map | Map |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
映射器(mappers)有细节注意点
方法1:配置资源路径
1 | <mappers> |
方法2:使用class绑定接口类
- 注意!!!接口和Mapper配置文件必须同名
- 接口和Mapper配置文件必须位于同一包下
1 | <mappers> |
方法3:扫描包进行注入绑定
- 注意!!!接口和Mapper配置文件必须同名
- 接口和Mapper配置文件必须位于同一包下
1 | <mappers> |
生命周期和作用域
生命周期和作用域的错误使用会导致严重的并发问题
SqlSessionFactory(局部变量)
一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。
SqlSessionFactory(应用作用域,全局变量)
SqlSessionFactory一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。类比数据库连接池。推荐使用单例模式。
SqlSession(方法作用域)
每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的。 用完就关,以防资源占用。
ResultMap(自定义映射关系)
当工具类中的和我们的数据库属性不一致时
1 | private int id; |
1 | 查询结果: |
解决办法:ResultMap结果集映射
1 | <resultMap id="UserMap" type="user"> |
1 | 查询结果: |
日志
以前报错看debug,现在选择多看日志。
- SLF4J
- LOG4J
- JDK_LOGGING
- COMMONS_LOGGING
- STDOUT_LOGGING
- NO_LOGGING
mybatis具体使用哪个自行设置
STDOUT_LOGGING 标准日志输出
1 | <settings> |
日志反馈
1 | Opening JDBC Connection |
LOG4J(推荐使用)
通过使用Log4j,我们可以控制日志信息输送的目的地;控制每一条日志的输出格式;通过定义每一条日志信息的级别,能更加细致地控制日志的生成过程。这些都可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
先导包
1
2
3
4
5<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>配置log4j.properties
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
DEBUG,console,file =
#控制台输出的相关设置
org.apache.log4j.ConsoleAppender =
System.out =
DEBUG =
org.apache.log4j.PatternLayout =
[%c]-%m%n =
#文件输出的相关设置
org.apache.log4j.RollingFileAppender =
./log/kuang.log =
10mb =
DEBUG =
org.apache.log4j.PatternLayout =
[%p][%d{yy-MM-dd}][%c]%m%n =
#日志输出级别
DEBUG =
DEBUG =
DEBUG =
DEBUG =
DEBUG =核心配置文件中设置日志
1
2
3<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>使用
导入org.apache.log4j.Logger,包别导错了
生成日志对象,参数为当前类class
1
Logger logger = Logger.getLogger(UserDaoTest.class)
使用logger对象来调试(就像之前做安卓,用日志语句输出,可以观测哪一些语句执行了,哪些没执行,进而找到问题出错的地方)
1
2
3
4
5
6
public void testLog4j(){
logger.info("info:调用testLog4j方法");
logger.debug("debug:调用tesLog4j方法");
logger.error("error:调用testLog4j方法");
}
分页
使用sql语句limit分页
接口
1
List<User> getUserLimit(Map<String,Integer> map);
配置mapper
1
2
3<select id="getUserLimit" parameterType="map" resultMap="UserMap">
select * from mybatis.user limit #{startIndex},#{pageSize}
</select>测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void getUserLimit(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("startIndex",0);
map.put("pageSize",3);
List<User> user = mapper.getUserLimit(map);
for(User u : user)
System.out.println(u);
sqlSession.close();
}
MyBatis PageHelper分页插件:https://pagehelper.github.io/
注解开发
基本流程
面向接口编程:解耦
接口和实现分离
这两点我有点联想到设计模式
反射机制+动态代理
使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让你本就复杂的 SQL 语句更加混乱不堪。 因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句。
定义接口
1
2
List<User> getUser();配置Mapper
1
2
3
4<!-- 绑定接口 -->
<mappers>
<mapper class="com.tang.dao.UserMapper"/>
</mappers>测试
1
2
3
4
5
6
7
8
9
public void getUser(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUser();
for(User user : userList)
System.out.println(user);
sqlSession.close();
}
MyBatis执行流程
在MyBatisUtils中
先获得核心配置文件
1
2String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);隐式的调用方法加载配置文件,build方法内部如图
1
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
然后sqlSessionFactory便被实例化
在测试、使用中调用接口,进而使用executor执行器(包括事务操作+CURD)
1
2SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
注解操作CURD
可在工具类实现自动提交事务,调用构造器自动提交
1
2
3public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession(true);
}实现接口后的对应方法:
1
2
3public SqlSession openSession(boolean autoCommit) {
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, autoCommit);
}接口添加注解(接口要及时注册到核心配置文件)
1
2
3
4
5
User getUserId(int id) ;
int addUser(User user);@Param:基本类型&String需要加上、sql中优先使用这里设置的属性名。
Lombok
相关评议:https://www.zhihu.com/question/42348457
就是一个偷懒工具,JavaBean中再也不用写get、set、toString以及构造器,通过注解即可搞定。
步骤:先在idea中安装插件,maven加入依赖,字段加入注解。
maven:
1 | <dependencies> |
可使用的注解:
1 | @Getter and @Setter |
工具类偷懒:
1 |
|
多对一、一对多(这个要多练,有点懵)
sql表创建,环境搭建
关联(多对一)
集合(一对多)
- sql语句,通过tid使学生与老师进行多对一的关联
1 | CREATE TABLE `teacher` ( |
- 导入lombok辅助实体类Teacher、Student(偷懒)
- 创建Mapper接口及其对应Mapper.xml
- MyBatis核心配置文件注册Mapper
association(多对一)
如果我们查询到时候只写了返回resultType类型,那么它只会返回对应的实体类,只是一个字段名,但我们要查的是老师这个对象,这时就要我们自定义。
其实重要的只有association语句,其他的result标签和resultType是一样的。
1 | <select id="getStudent" resultType="Student"> |
自定义resultMap查询
- 方法一:查询嵌套。子查询,先查找学生表,再查找老师表中的对应信息进行赋值。
1 | <!-- 查询所有学生信息,根据查询到学生tid,再查找对应的老师 |
- 方法二:结果嵌套
1 | <!-- 结果嵌套 --> |
两种查询方法,子查询是先查一个表,然后再关联另一个表查询对应字段属性;而结果查询是先把完整的查找语句打出来,然后自行定义其中的字段关系。
collection(一对多)
- 方法一:子查询
1 | <select id="getTeacher2" resultMap="TeacherStudent2"> |
- 方法二:结果嵌套
1 | <select id="getTeacher" resultMap="TeacherStudent"> |
注意
JavaType和ofType都是用来指定对象类型的,但是JavaType是用来指定pojo中属性的类型,而ofType指定映射到list集合属性中pojo的类型。
动态SQL
sql创建表单,然后自行搭建测试环境
1 | CREATE TABLE `blog`( |
IF
可以发现,通过if进行条件过滤,实行动态sql语句,当我们存入author相关属性,则会定向到查询对应author,其他字段也是如此。
Mapper.xml
1 | <!-- if语句若通过则执行其中内容--> |
测试类
1 |
|
choose、when、otherwise
choose、when、otherwise类似switch、case、default,
不同点:没有输出的sql拼接语句长这样,会view=?,这样就查不出结果了
1 | select * from mybatis.blog WHERE views = ? |
Mapper.xml
1 | <select id="queryBlogChoose" parameterType="map" resultType="blog"> |
测试类
1 |
|
trim、where、set
where
首先说说where,可以看上面的if和choose进行对比,if中没有使用where标签,和后面语句的衔接明显有问题,还必须加入1=1这个废句子来强行拼接合理,而choose中使用了where标签就顺滑多了。
where元素只会在有返回内容时下才插入 “WHERE”的sql 子句,在choose中若没写otherwise且无when判断成功,则不会输出“WHERE”。当第一个子句的开头为 “AND” 或 “OR”时,where 元素也会将它们去除。
set(用于更新)
因为update ··· set,set用于sql更新语句的。
set标签会在有内容时加入set,并删除多余的尾部逗号,因为sql更新属性时,属性间用逗号隔开,最后一个无逗号。
1
2
3
4
5
6
7
8
9
10
11
12<update id="updateBlog" parameterType="map">
update mybatis.blog
<set>
<if test="title!=null">
title=#{title},
</if>
<if test="author!=null">
author=#{author},
</if>
</set>
where id=#{id}
</update>trim(自定义)
prefix前缀,prefixOverrides前缀覆盖
suffix后缀,suffixOverrides后缀覆盖
1
2
3
4
5
6
7
8
9<!-- 类似where,可替代where标签-->
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
<!-- 类似set,可替代set标签-->
<trim prefix="SET" suffixOverrides=",">
...
</trim>
Foreach(遍历)
Mapper.xml
集合、集合项、开头。分隔符、结尾
1 | <select id="queryBlogForeach" parameterType="map" resultType="blog"> |
测试类:传入一个list,然后select中会遍历该list的id并拼接
1 |
|
SQL片段
提取重复sql语句,变为sql片段,然后在要使用时引用
使用sql标签提取公共片段
1
2
3
4
5
6
7
8<sql id="if">
<if test="title!=null">
title = #{title}
</if>
<if test="author!=null">
and author = #{author}
</if>
</sql>引用时使用include标签,refid对应片段id
1
2
3
4
5
6<select id="queryBlogIF" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<include refid="if"></include>
</where>
</select>
小结
动态SQL就是加入了一些选择性的判断语句。而且我们在sql中常常需要注意标点符号的使用,多写漏写都会报错,使用动态sql就省去了省查符号的步骤,总的来说还是为了方便自身。
缓存
存在内存中的临时数据,不用每次都去数据库查询,直接在缓存中查询,提高查询效率,解决高并发等性能问题。常常要查询且不常改变的数据应使用缓存。
默认的清除策略:
LRU
– 最近最少使用:移除最长时间不被使用的对象。FIFO
– 先进先出:按对象进入缓存的顺序来移除它们。SOFT
– 软引用:基于垃圾回收器状态和软引用规则移除对象。WEAK
– 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。
一级缓存(本地缓存)
一级缓存即本地缓存:SqlSession,默认开启
与数据库同一次会话期间查询到的数据会放在本地缓存。在SqlSession未关闭期间,若获得相同数据直接从缓存中拿取,不要再查询数据库。
测试
setting中要配置日志查看反馈
测试在一次Session中查询两次相同的sql,发现只查一次sql语句,但两次都有结果,因为默认开启一级缓存,第二次查询直接加载第一次的。
缓存失效:
查询不同数据。中途有增删改操作,可能会改变原有数据,缓存刷新。
手动清理。
一级缓存默认开启,只在一次SqlSession开启到关闭间有效。
1 |
|
二级缓存(全局缓存)
- 机制
- 一个会话查询一条数据,数据会放在当前会话的一级缓存
- 会话关闭后,该会话一级缓存就消失了;但可以把该一级缓存保存到二级缓存中
- 新会话的查询信息,可以从二级缓存中获取内容
首先要开启全局缓存
1 | <setting name="cacheEnabled" value="true"/> |
使用二级缓存,开启二级缓存,还可以自定义一些属性
1 | <cache/> |
注意pojo实体类要实现Serializable接口,将实体类序列化,否则使用单cache标签时会报错
1 | Cause: java.io.NotSerializableException: com.tang.pojo.User |
测试:
在关闭第一个SqlSession后,由于开启了二级缓存,SqlSession1仍会拿到缓存不用查询数据库
1 |
|
查询:二级缓存————》一级缓存————》数据库
自定义缓存-ehcache(现在用Redis数据库来缓存)
maven导包
1 | <!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache --> |
Mapper配置
1 | <cache type="org.mybatis.caches.ehcache.EhcacheCache"/> |
配置文件ehcache.xml
1 |
|
还可以自行写一个类实现cache接口来实现自定义缓存
小结
下一步Spring MVC,学完SSM赶紧搞个小项目!!