一、第一个Mybatis程序
Mybatis中文文档:https://mybatis.org/mybatis-3/zh/index.html
(一)创建数据库 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 //创建数据库 create databases mybatis;//使用数据库 user mybatis; //创建表 CREATE TABLE `user` ( `id` int (11 ) NOT NULL , `name` varchar (255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL , `pwd` varchar (255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL , PRIMARY KEY (`id` ) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; //添加数据 INSERT INTO `user` VALUES (1 , '张三' , '123456' );INSERT INTO `user` VALUES (2 , '李四' , '111111' );INSERT INTO `user` VALUES (3 , '王五' , '232323' );
(二)创建Maven工程 1.创建父工程
2.创建子工程
2.导入jar包
在父工程的pom文件中添加同样会在子工程作用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <dependencies > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.4.6</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 5.1.38</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.13</version > </dependency > </dependencies >
3.加入maven静态文件过滤
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <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 >
(三)基本使用Mybatis 1.编写MyBatis核心配置文件 在resources中创建mybatis-config.xml
1.com.mysql.jdbc.Driver mysql数据库
2.url: 连接数据库的url 如果后面带参数,&
用&
代替
3.root 数据库用户
4.love1314 数据库密码
5. (非常重要) mapper的配置文件,每一个mapper文件都要在配置中心注册
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?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 > <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?useUnicode=true& characterEncoding=utf8& useSSL=false" /> <property name ="username" value ="root" /> <property name ="password" value ="love1314" /> </dataSource > </environment > </environments > <mappers > <mapper resource ="com/myth/dao/UserMapper.xml" /> </mappers > </configuration >
2.编写MyBatis工具类 在utils包中创建MybatisUtils
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 package com.myth.utils;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 java.io.IOException;import java.io.InputStream;public class MybatisUtils { private static SqlSessionFactory sqlSessionFactory; static { try { String resource = "mybatis-config.xml" ; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession () { return sqlSessionFactory.openSession(); } }
3.创建实体类 在pojo中创建User 实体类
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 package com.myth.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 + '\'' + '}' ; } }
4.编写Mapper接口类 在dao层创建UserDao接口
1 2 3 4 5 6 7 8 9 10 11 12 package com.myth.dao;import com.myth.pojo.User;import java.util.List;public interface UserDao { List<User> getUserList () ; }
5.编写Mapper.xml配置文件 在dao层创建UserMapper.xml
namespace:UserDao接口的路径
id:接口中的方法
resultType:接口返回的数据类型的路径
select * from user :sql语句
1 2 3 4 5 6 7 8 9 10 <?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.myth.dao.UserDao" > <select id ="getUserList" resultType ="com.myth.pojo.User" > select * from user </select > </mapper >
6.编写测试类 在test中创建测试类UserDaoTest
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 package com.myth.dao;import com.myth.pojo.User;import com.myth.utils.MybatisUtils;import org.apache.ibatis.session.SqlSession;import org.junit.Test;import java.util.List;public class UserDaoTest { @Test public void test () { SqlSession sqlSession = MybatisUtils.getSqlSession(); try { UserDao userDao = sqlSession.getMapper(UserDao.class); List<User> userList = userDao.getUserList(); for (User user : userList) { System.out.println(user); } } catch (Exception e) { e.printStackTrace(); }finally { sqlSession.close(); } } }
7.最终项目结构目录
8.运行结果
二、CRUD
1.建议将Dao层的UserDao改成UserMapper
2.一定要将接口的名称与xml中配置的namespace一样
3.增删改一定要记得提交事务commit
\
4.如果传递多个参数,可以使用Map的键值对形式传递多个参数。
5.如果是模糊查询,最好传递通配符% %,如:select * from user where name like "%"#{name}"%"
(一)SELECT UserMapper
1 2 3 4 List<User> getUserList () ;User getUserById (int id) ;
UserMapper.xml
1 2 3 4 5 6 7 <select id ="getUserList" resultType ="com.myth.pojo.User" > select * from user </select > <select id ="getUserById" parameterType ="int" resultType ="com.myth.pojo.User" > select * from user where id = #{id} </select >
单元测试类
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 @Test public void test01 () { SqlSession sqlSession = MybatisUtils.getSqlSession(); try { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> userList = userMapper.getUserList(); for (User user : userList) { System.out.println(user); } } catch (Exception e) { e.printStackTrace(); }finally { sqlSession.close(); } } @Test public void test02 () { SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.getUserById(2 ); System.out.println(user); sqlSession.close(); }
(二)INSERT UserMapper
1 2 int addUser (User user) ;
UserMapper.xml
1 2 3 <insert id ="addUser" parameterType ="com.myth.pojo.User" > insert into user(id,name,pwd) values (#{id},#{name},#{pwd}) </insert >
单元测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Test public void test03 () { SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); int add = mapper.addUser(new User(4 , "赵六" , "123456" )); if (add>0 ){ System.out.println("插入成功!" ); } sqlSession.commit(); sqlSession.close(); }
(三)UPDATE UserMapper
1 2 int updateUser (User user) ;
UserMapper.xml
1 2 3 <update id ="updateUser" parameterType ="com.myth.pojo.User" > update user set name=#{name},pwd=#{pwd} where id=#{id}; </update >
单元测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Test public void test04 () { SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); int a = mapper.updateUser(new User(4 , "赵小姐" , "111111" )); if (a>0 ){ System.out.println("修改成功!" ); } sqlSession.commit(); sqlSession.close(); }
(四)DELETE UserMapper
1 2 int deleteUser (int id) ;
UserMapper.xml
1 2 3 <delete id ="deleteUser" parameterType ="int" > delete from user where id=#{id} </delete >
单元测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Test public void test05 () { SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); int i = mapper.deleteUser(4 ); if (i>0 ){ System.out.println("删除成功!" ); } sqlSession.commit(); sqlSession.close(); }
三、XML配置 ## 1.核心配置文件
mybatis-config.xml
系统核心配置文件.
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。
xml文件配置顺序:
1 2 3 4 5 6 7 8 9 10 11 12 13 configuration(配置) properties(属性) settings(设置) typeAliases(类型别名) typeHandlers(类型处理器) objectFactory(对象工厂) plugins(插件) environments(环境配置) environment(环境变量) transactionManager(事务管理器) dataSource(数据源) databaseIdProvider(数据库厂商标识) mappers(映射器)
2.环境配置(environments) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <environments default ="development" > <environment id ="development" > <transactionManager type ="JDBC" > <property name ="..." value ="..." /> </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 > <environment id ="test" > <transactionManager type ="JDBC" > <property name ="..." value ="..." /> </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 >
配置MyBatis的多套运行环境,将SQL映射到多个不同的数据库上,必须指定其中一个为默认运行环境(通过default指定)
事务管理器(transactionManager)
默认为JDBC(还有一个MANAGED 不常用)
数据源(dataSource)
dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
大多数 MyBatis 应用程序会按示例中的例子来配置数据源。虽然数据源配置是可选的,但如果要启用延迟加载特性,就必须配置数据源。
有三种内建的数据源类型(也就是 type=”[UNPOOLED|POOLED|JNDI]”):
3.属性(properties) 这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。
优化配置文件
(1)在资源目录下新建一个db.properties
1 2 3 4 driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&useSSL=false username=root password=love1314
(2)将文件导入properties 配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <configuration > <properties resource ="db.properties" > </properties > <environments default ="development" > <environment id ="development" > <transactionManager type ="JDBC" /> <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 > <mappers > <mapper resource ="com/myth/dao/UserMapper.xml" /> </mappers > </configuration >
xml中的property加载顺序
高——>低
通过方法参数传递——>resource/url 属性中指定的配置文件——>properties 元素中指定的属性
4.类型别名(typeAliases) 类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:
1 2 3 4 5 6 7 8 <typeAliases > <typeAlias alias ="Author" type ="domain.blog.Author" /> <typeAlias alias ="Blog" type ="domain.blog.Blog" /> <typeAlias alias ="Comment" type ="domain.blog.Comment" /> <typeAlias alias ="Post" type ="domain.blog.Post" /> <typeAlias alias ="Section" type ="domain.blog.Section" /> <typeAlias alias ="Tag" type ="domain.blog.Tag" /> </typeAliases >
当这样配置时,Blog
可以用在任何使用 domain.blog.Blog
的地方。
也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
1 2 3 <typeAliases > <package name ="domain.blog" /> </typeAliases >
每一个在包 domain.blog
中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写
的非限定类名来作为它的别名。 比如 domain.blog.Author
的别名为 author
;若有注解,则别名为其注解值。见下面的例子:
1 2 3 4 @Alias("author") public class Author { ... }
5.设置(settings) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <settings > <setting name ="cacheEnabled" value ="true" /> <setting name ="lazyLoadingEnabled" value ="true" /> <setting name ="multipleResultSetsEnabled" value ="true" /> <setting name ="useColumnLabel" value ="true" /> <setting name ="useGeneratedKeys" value ="false" /> <setting name ="autoMappingBehavior" value ="PARTIAL" /> <setting name ="autoMappingUnknownColumnBehavior" value ="WARNING" /> <setting name ="defaultExecutorType" value ="SIMPLE" /> <setting name ="defaultStatementTimeout" value ="25" /> <setting name ="defaultFetchSize" value ="100" /> <setting name ="safeRowBoundsEnabled" value ="false" /> <setting name ="mapUnderscoreToCamelCase" value ="false" /> <setting name ="localCacheScope" value ="SESSION" /> <setting name ="jdbcTypeForNull" value ="OTHER" /> <setting name ="lazyLoadTriggerMethods" value ="equals,clone,hashCode,toString" /> </settings >
6.映射器(mappers) 方式一:使用相对于类路径的资源引用【推荐】
1 2 3 4 5 <mappers > <mapper resource ="org/mybatis/builder/AuthorMapper.xml" /> <mapper resource ="org/mybatis/builder/BlogMapper.xml" /> <mapper resource ="org/mybatis/builder/PostMapper.xml" /> </mappers >
方式二:使用映射器接口实现类的完全限定类名
1 2 3 4 5 <mappers > <mapper class ="org.mybatis.builder.AuthorMapper" /> <mapper class ="org.mybatis.builder.BlogMapper" /> <mapper class ="org.mybatis.builder.PostMapper" /> </mappers >
方式三:将包内的映射器接口实现全部注册为映射器
1 2 3 <mappers > <package name ="org.mybatis.builder" /> </mappers >
使用方式二和方式三需要满足条件:
接口和他的Mapper配置文件必须同名。
接口和他的Mapper配置文件必须在同一包下。
7.作用域(Scope)和生命周期 SqlSessionFactoryBuilder 这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法 变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。
SqlSessionFactory SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次 ,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域 。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
SqlSession 每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的 ,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域 。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要 ,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。 下面的示例就是一个确保 SqlSession 关闭的标准模式:
1 2 3 try (SqlSession session = sqlSessionFactory.openSession()) { }
在所有代码中都遵循这种使用模式,可以保证所有数据库资源都能被正确地关闭。
四、XML映射
前提问题:如果实体类创建的名称与数据库中的名称不相同,则查到的结果可能为null,这是因为没有使用结果集映射。
方案一:为列名指定别名 , 别名和java实体类的属性名一致 .
1 2 3 <select id ="selectUserById" resultType ="User" > select id , name , pwd as password from user where id = #{id} </select >
方案二:使用结果集映射ResultMap(推荐)
1 2 3 4 5 6 7 8 9 10 11 <resultMap id ="UserMap" type ="User" > <id column ="id" property ="id" /> <result column ="name" property ="name" /> <result column ="pwd" property ="password" /> </resultMap > <select id ="selectUserById" resultMap ="UserMap" > select id , name , pwd from user where id = #{id} </select >
五、日志 1.日志工厂
标准日志(写在mybatis-config.xml)
1 2 3 <settings > <setting name ="logImpl" value ="STDOUT_LOGGING" /> </settings >
结果:
2.log4j 1、导入log4j的包
1 2 3 4 5 <dependency > <groupId > log4j</groupId > <artifactId > log4j</artifactId > <version > 1.2.17</version > </dependency >
2、配置文件编写(在resource中新建一个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 log4j.rootLogger =DEBUG,console,file log4j.appender.console = org.apache.log4j.ConsoleAppender log4j.appender.console.Target = System.out 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.RollingFileAppender log4j.appender.file.File =./log/myth.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 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、setting设置日志实现
1 2 3 <settings > <setting name ="logImpl" value ="LOG4J" /> </settings >
六、Mybatis实现分页 步骤:
1.写接口
1 2 List<User> selectUser (Map<String,Integer> map) ;
2.写xml
1 2 3 <select id ="selectUser" parameterType ="map" resultMap ="UserMap" > select * from user limit #{startIndex},#{pageSize} </select >
3.写测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 @Test public void selectUser () { SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); HashMap<String,Integer> map = new HashMap<String, Integer>(); map.put("startIndex" ,2 ); map.put("pageSize" ,2 ); List<User> userList = mapper.selectUser(map); for (User user : userList) { System.out.println(user); } sqlSession.close(); }
还可以使用mybatis插件,PageHelper
https://pagehelper.github.io/
七、使用注解开发 (1)面向接口编程
大家之前都学过面向对象编程,也学习过接口,但在真正的开发中,很多时候我们会选择面向接口编程
根本原因 : 解耦 , 可拓展 , 提高复用 , 分层开发中 , 上层不用管具体的实现 , 大家都遵守共同的标准 , 使得开发变得容易 , 规范性更好
在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了;
而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程。
关于接口的理解
三个面向区别
面向对象是指,我们考虑问题时,以对象为单位,考虑它的属性及方法 .
面向过程是指,我们考虑问题时,以一个具体的流程(事务过程)为单位,考虑它的实现 .
接口设计与非接口设计是针对复用技术而言的,与面向对象(过程)不是一个问题.更多的体现就是对系统整体的架构
(2)使用注解开发
使用接口就不需要mapper.xml映射文件
实现步骤:
1、接口添加注解
1 2 3 @Select("select * from user") public List<User> getAllUser () ;
2、在mybatis的核心配置文件中注入
1 2 3 4 <mappers > <mapper class ="com.myth.mapper.UserMapper" /> </mappers >
3、测试
1 2 3 4 5 6 7 8 9 10 @Test public void getUserList () { 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(); }
(3)使用注解CRUD
1.使用注解时,一定要绑定所在Mapper
2.确保实体类和数据库字段对应
改造MybatisUtils工具类的getSession( ) 方法,重载实现,实现事务自动提交
1 2 3 4 5 6 7 8 public static SqlSession getSession () { return getSession(true ); } public static SqlSession getSession (boolean flag) { return sqlSessionFactory.openSession(flag); }
确保实体类和数据库字段对应
查询 1、编写接口方法注解
param中的id和select语句中的id对应
1 2 3 @Select("select * from user where id = #{id}") User selectUserById (@Param("id") int id) ;
2、测试
1 2 3 4 5 6 7 8 9 10 @Test public void testSelectUserById () { SqlSession sqlsession = MybatisUtils.getSession(); UserMapper mapper = sqlsession.getMapper(UserMapper.class); User user = mapper.selectUserById(1 ); System.out.println(user); sqlsession.close(); }
新增 1、编写接口方法注解
1 2 3 @Insert("insert into user (id,name,pwd) values (#{id},#{name},#{pwd})") int addUser (User user) ;
2、测试
1 2 3 4 5 6 7 8 9 10 @Test public void testAddUser () { SqlSession sqlsession = MybatisUtils.getSession(); UserMapper mapper = sqlsession.getMapper(UserMapper.class); User user = new User(6 , "赵留" , "123456" ); mapper.addUser(user); sqlsession.close(); }
修改 1、编写接口方法注解
1 2 3 @Update("update user set name=#{name},pwd=#{pwd} where id = #{id}") int updateUser (User user) ;
2、测试
1 2 3 4 5 6 7 8 9 10 @Test public void testUpdateUser () { SqlSession sqlsession = MybatisUtils.getSession(); UserMapper mapper = sqlsession.getMapper(UserMapper.class); User user = new User(6 , "赵六" , "777777" ); mapper.updateUser(user); sqlsession.close(); }
删除 1、编写接口方法注解
1 2 3 @Delete("delete from user where id = #{id}") int deleteUser (@Param("id") int id) ;
2、测试
1 2 3 4 5 6 7 8 9 @Test public void testDeleteUser () { SqlSession sqlsession = MybatisUtils.getSession(); UserMapper mapper = sqlsession.getMapper(UserMapper.class); mapper.deleteUser(6 ); sqlsession.close(); }
(4)@Param
基本类型的参数或者String类型需要加上
引用类型不需要加
如果只有一个基本类型,可以忽略,但建议加上
我们在SQL中引用的就是我们这里的@param()中的设定的属性名
(5)#与$的区别 1、#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by “111”, 如果传入的值是id,则解析成的sql为order by “id”.
2、$将传入的数据直接显示生成在sql中。如:order by $user_id$,如果传入的值是111,那么解析成sql时的值为order by user_id, 如果传入的值是id,则解析成的sql为order by id.
3、#方式能够很大程度防止sql注入。
4、$方式无法防止Sql注入。
5、$方式一般用于传入数据库对象,例如传入表名. 6、一般能用#的就别用$.
MyBatis排序时使用order by 动态参数时需要注意,用$而不是#
字符串替换 默认情况下,使用#{}格式的语法会导致MyBatis创建预处理语句属性并以它为背景设置安全的值(比如?)。这样做很安全,很迅速也是首选做法,有时你只是想直接在SQL语句中插入一个不改变的字符串。比如,像ORDER BY,你可以这样来使用: ORDER BY ${columnName} 这里MyBatis不会修改或转义字符串。
重要:接受从用户输出的内容并提供给语句中不变的字符串,这样做是不安全的。这会导致潜在的SQL注入攻击,因此你不应该允许用户输入这些字段,或者通常自行转义并检查。
八、复杂关系处理 (0)环境搭建 数据库设计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 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` (`id` , `name` , `tid` ) VALUES ('1' , '张三' , '1' );INSERT INTO `student` (`id` , `name` , `tid` ) VALUES ('2' , '李四' , '1' );INSERT INTO `student` (`id` , `name` , `tid` ) VALUES ('3' , '王五' , '1' );INSERT INTO `student` (`id` , `name` , `tid` ) VALUES ('4' , '赵六' , '1' );INSERT INTO `student` (`id` , `name` , `tid` ) VALUES ('5' , '钱七' , '1' );
搭建环境
1、IDEA安装Lombok插件
2、引入Maven依赖
1 2 3 4 5 6 <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > 1.18.12</version > <scope > provided</scope > </dependency >
3、在代码中增加注解
1 2 3 4 5 6 7 @Data @AllArgsConstructor @NoArgsConstructor public class Teacher { private int id; private String name; }
1 2 3 4 5 6 7 8 @Data @AllArgsConstructor @NoArgsConstructor public class Student { private int id; private String name; private Teacher teacher; }
4、编写实体类对应的Mapper接口
1 2 public interface StudentMapper {}
1 2 public interface TeacherMapper {}
5、编写Mapper接口对应的 mapper.xml配置文件
1 2 3 4 5 6 7 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="com.myth.dao.TeacherMapper" > </mapper >
1 2 3 4 5 6 7 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="com.myth.dao.StudentMapper" > </mapper >
6、核心配置文件绑定xml文件
1 2 3 <mappers > <package name ="com.myth.dao" /> </mappers >
(1)多对一 按查询嵌套处理
1、给StudentMapper接口增加方法
1 2 public List<Student> getStudents () ;
2、编写对应的Mapper文件
注意别名
注意在配置文件中注册Mapper
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="com.myth.dao.StudentMapper" > <select id ="getStudent" resultMap ="studentwithteacher" > select * from student </select > <resultMap id ="studentwithteacher" type ="Student" > <result property ="id" column ="id" /> <result property ="name" column ="name" /> <association property ="teacher" column ="tid" javaType ="Teacher" select ="getTeacher" /> </resultMap > <select id ="getTeacher" resultType ="Teacher" > select * from teacher where id = #{id} </select > </mapper >
3、注意点说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 <resultMap id ="StudentTeacher" type ="Student" > <association property ="teacher" column ="tid" javaType ="Teacher" select ="getTeacher" /> </resultMap > <select id ="getTeacher" resultType ="teacher" > select * from teacher where id = #{id} and name = #{name} </select >
4、测试
1 2 3 4 5 6 7 8 9 10 @Test public void testStudent () { SqlSession sqlSession = MybatisUtils.getSqlSession(); StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); List<Student> studentlist = mapper.getStudent(); for (Student student : studentlist) { System.out.println(student); } sqlSession.close(); }
按结果嵌套处理
1、接口方法编写
1 public List<Student> getStudents2 () ;
2、编写对应的mapper文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <select id ="getStudents2" resultMap ="StudentTeacher2" > select s.id sid, s.name sname , t.name tname from student s,teacher t where s.tid = t.id </select > <resultMap id ="StudentTeacher2" type ="Student" > <id property ="id" column ="sid" /> <result property ="name" column ="sname" /> <association property ="teacher" javaType ="Teacher" > <result property ="name" column ="tname" /> </association > </resultMap >
3、测试
1 2 3 4 5 6 7 8 9 10 @Test public void testStudent2 () { SqlSession sqlSession = MybatisUtils.getSqlSession(); StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); List<Student> student2List = mapper.getStudent2(); for (Student student : student2List) { System.out.println(student); } sqlSession.close(); }
(2)一对多 实体类修改
1 2 3 4 5 6 7 8 @Data @AllArgsConstructor @NoArgsConstructor public class Student { private int id; private String name; private int tid; }
1 2 3 4 5 6 7 8 @Data @AllArgsConstructor @NoArgsConstructor public class Teacher { private int id; private String name; private List<Student> students; }
按结果嵌套处理
1、TeacherMapper接口编写方法
1 2 3 4 Teacher getTeacher (@Param("tid") int id) ;
2、编写接口对应的Mapper配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="com.myth.dao.TeacherMapper" > <select id ="getTeacher" resultMap ="TeacherStudent" > select t.id tid,t.name tname,s.id sid,s.name sname from teacher t,student s where t.id=s.tid and t.id=#{tid}; </select > <resultMap id ="TeacherStudent" type ="Teacher" > <result property ="id" column ="tid" /> <result property ="name" column ="tname" /> <collection property ="students" ofType ="Student" > <result property ="id" column ="sid" /> <result property ="name" column ="sname" /> <result property ="tid" column ="tid" /> </collection > </resultMap > </mapper >
3、将Mapper文件注册到MyBatis-config文件中
1 2 3 <mappers > <package name ="com.myth.dao" /> </mappers >
4、测试
1 2 3 4 5 6 7 @Test public void testteacher () { SqlSession sqlSession = MybatisUtils.getSqlSession(); TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class); Teacher teacher = mapper.getTeacher(1 ); System.out.println(teacher); }
按查询嵌套处理
1、TeacherMapper接口编写方法
1 Teacher getTeacher2 (int id) ;
2、编写接口对应的Mapper配置文件
1 2 3 4 5 6 7 8 9 <select id ="getTeacher2" resultMap ="TeacherStudent2" > select * from teacher where id = #{id} </select > <resultMap id ="TeacherStudent2" type ="Teacher" > <collection property ="students" javaType ="ArrayList" ofType ="Student" column ="id" select ="getStudentByTeacherId" /> </resultMap > <select id ="getStudentByTeacherId" resultType ="Student" > select * from student where tid = #{tid} </select >
3、将Mapper文件注册到MyBatis-config文件中
1 2 3 <mappers > <package name ="com.myth.dao" /> </mappers >
4、测试
1 2 3 4 5 6 7 8 @Test public void testteacher2 () { SqlSession sqlSession = MybatisUtils.getSqlSession(); TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class); Teacher teacher2 = mapper.getTeacher2(1 ); System.out.println(teacher2); }
(3)总结 1、关联—association—-【多对一】
2、集合—collection—-【一对多】
3、javaType & ofType
1、javaType 用来指定实体类中属性的类型
2、ofType 用来指定映射到List或者集合中的pojo类型,泛型中的约束类型!
注意点:
1、保证SQL的可读性,尽量通俗易懂
2、根据实际要求,尽量编写性能更高的SQL语句
3、注意属性名和字段不一致的问题
4、注意一对多和多对一 中:字段和属性对应的问题
5、尽量使用Log4j,通过日志来查看自己的错误
面试高频
九、动态SQL
官方文档:https://mybatis.org/mybatis-3/zh/dynamic-sql.html
介绍 动态SQL就是指根据不同的条件生成不同的SQL语句
动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。
如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。
if
choose (when, otherwise)
trim (where, set)
foreach
环境搭建 (1)新建一个数据库表:blog
1 2 3 4 5 6 7 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
(2)创建Mybatis基础工程(图为最终成果)
(3)工具类
MybatisUtils(注意:这里设置了自动提交事务)
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 package com.myth.utils;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 java.io.IOException;import java.io.InputStream;public class MybatisUtils { private static SqlSessionFactory sqlSessionFactory; static { try { String resource = "mybatis-config.xml" ; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession () { return sqlSessionFactory.openSession(true ); } }
IDUtil
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package com.myth.utils;import org.junit.Test;import java.util.UUID;public class IDUtil { public static String genId () { return UUID.randomUUID().toString().replaceAll("-" ,"" ); } }
(4)实体类(这里使用了LomBok生成get/set)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package com.myth.pojo;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import java.util.Date;@Data @AllArgsConstructor @NoArgsConstructor public class Blog { private String id; private String title; private String author; private Date createTime; private int views; }
(5)编写Mapper接口及xml文件(这里我是将接口类和xml文件放在同一目录)
1 2 3 public interface BlogMapper {}
1 2 3 4 5 6 7 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="com.myth.dao.BlogMapper" > </mapper >
(6)修改mybatis核心配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 <settings > <setting name ="mapUnderscoreToCamelCase" value ="true" /> <setting name ="logImpl" value ="STDOUT_LOGGING" /> </settings > <typeAliases > <package name ="com.myth.pojo" /> </typeAliases > <mappers > <mapper resource ="mapper/BlogMapper.xml" /> </mappers >
(7)插入初始数据
编写接口
1 2 int addBlog (Blog blog) ;
sql配置文件
1 2 3 4 <insert id ="addBlog" parameterType ="blog" > insert into blog (id, title, author, create_time, views) values (#{id},#{title},#{author},#{createTime},#{views}); </insert >
初始化博客方法
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 @Test public void insert () { SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); Blog blog = new Blog(); blog.setId(IDUtil.genId()); blog.setTitle("JAVA从入门到放弃" ); blog.setAuthor("Bruce Eckel" ); blog.setCreateTime(new Date()); blog.setViews(9999 ); mapper.addBlog(blog); blog.setId(IDUtil.genId()); blog.setTitle("MYSQL从入门到跑路" ); blog.setAuthor("MYSQL" ); blog.setCreateTime(new Date()); blog.setViews(8888 ); mapper.addBlog(blog); blog.setId(IDUtil.genId()); blog.setTitle("C语言从入门到入坟" ); blog.setAuthor("C" ); blog.setCreateTime(new Date()); blog.setViews(7777 ); mapper.addBlog(blog); blog.setId(IDUtil.genId()); blog.setTitle("Python从入门到崩溃" ); blog.setAuthor("Python" ); blog.setCreateTime(new Date()); blog.setViews(6666 ); mapper.addBlog(blog); sqlSession.close(); }
IF 需求:根据作者名字和博客名字来查询博客!如果作者名字为空,那么只根据博客名字查询,反之,则根据作者名来查询
1、编写接口类
1 List<Blog> queryBlogIf (Map map) ;
2、编写SQL语句
1 2 3 4 5 6 7 8 9 10 11 <select id ="queryBlogIf" parameterType ="map" resultType ="blog" > select * from blog where 1=1 <if test ="title != null" > and title = #{title} </if > <if test ="author != null" > and author= #{author} </if > </select >
3、测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Test public void queryBlogIf () { SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); map.put("title" ,"JAVA从入门到放弃" ); map.put("author" ,"Bruce Eckel" ); List<Blog> blogs = mapper.queryBlogIf(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
WHERE 修改上面的SQL语句:
1 2 3 4 5 6 7 8 9 10 11 <select id ="queryBlogIf" parameterType ="map" resultType ="blog" > select * from blog <where > <if test ="title != null" > title = #{title} </if > <if test ="author != null" > and author = #{author} </if > </where > </select >
这个“where”标签会知道如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以AND 或OR 开头的,则它会剔除掉。
SET 同理,上面的对于查询 SQL 语句包含 where 关键字,如果在进行更新操作的时候,含有 set 关键词,我们怎么处理呢?
1、编写接口方法
1 int updateBlog (Map map) ;
2、sql配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 <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}; </update >
3、测试
1 2 3 4 5 6 7 8 9 10 11 @Test public void updateBlog () { SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); map.put("id" ,"fc8dbafbea6746b7a330731f1c17d541" ); map.put("author" ,"JAVA" ); mapper.updateBlog(map); sqlSession.close(); }
CHOOSE 有时候,我们不想用到所有的查询条件,只想选择其中的一个,查询条件有一个满足即可,使用 choose 标签可以解决此类问题,类似于 Java 的 switch 语句
1、编写接口方法
1 List<Blog> queryBlogChoose (Map map) ;
2、sql配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <select id ="queryBlogChoose" parameterType ="map" resultType ="blog" > select * from blog <where > <choose > <when test ="title != null" > title = #{title} </when > <when test ="author != null" > and author = #{author} </when > <otherwise > and views > #{views} </otherwise > </choose > </where > </select >
3、测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Test public void queryBlogChoose () { SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); map.put("title" ,"JAVA从入门到放弃" ); map.put("author" ,"Python" ); map.put("views" ,7777 ); List<Blog> blogs = mapper.queryBlogChoose(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
SQL片段 有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。
提取SQL片段:
1 2 3 4 5 6 7 8 <sql id ="if-title-author" > <if test ="title != null" > title = #{title} </if > <if test ="author != null" > and author = #{author} </if > </sql >
引用SQL片段:
1 2 3 4 5 6 7 8 <select id ="queryBlogIf" parameterType ="map" resultType ="blog" > select * from blog <where > <include refid ="if-title-author" > </include > </where > </select >
注意:
1.最好基于 单表来定义 sql 片段,提高片段的可重用性
2.在 sql 片段中不要包括 where
Foreach 将数据库中前三个数据的id修改为1,2,3;
需求:我们需要查询 blog 表中 id 分别为1,2,3的博客信息
1、编写接口
1 List<Blog> queryBlogForeach (Map map) ;
2、编写SQL语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <select id ="queryBlogForeach" parameterType ="map" resultType ="blog" > select * from blog <where > <foreach collection ="ids" item ="id" open ="and (" close =")" separator ="or" > id=#{id} </foreach > </where > </select >
3、测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Test public void testQueryBlogForeach () { SqlSession sqlsession = MybatisUtils.getSession(); BlogMapper mapper = sqlsession.getMapper(BlogMapper.class); HashMap map = new HashMap(); List<Integer> ids = new ArrayList<Integer>(); ids.add(1 ); ids.add(2 ); ids.add(3 ); map.put("ids" ,ids); List<Blog> blogs = mapper.queryBlogForeach(map); System.out.println(blogs); sqlsession.close(); }
十、缓存 简介 1、什么是缓存 [ Cache ]?
存在内存中的临时数据。
将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。
2、为什么使用缓存?
减少和数据库的交互次数,减少系统开销,提高系统效率。
3、什么样的数据能使用缓存?
Mybatis缓存
一级缓存 一级缓存也叫本地缓存:
与数据库同一次会话期间查询到的数据会放在本地缓存中。
以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库;
测试:
1、在mybatis中加入日志,方便测试结果
2、编写接口方法
1 2 User queryUserById (@Param("id") int id) ;
3、接口对应的Mapper文件
1 2 3 <select id ="queryUserById" resultType ="user" > select * from user where id = #{id} </select >
4、测试
1 2 3 4 5 6 7 8 9 10 11 12 13 @Test public void testQueryUserById () { SqlSession session = MybatisUtils.getSession(); UserMapper mapper = session.getMapper(UserMapper.class); User user = mapper.queryUserById(1 ); System.out.println(user); User user2 = mapper.queryUserById(1 ); System.out.println(user2); System.out.println(user==user2); session.close(); }
一级缓存失效的四种情况:
1、sqlSession不同
2、sqlSession相同,查询条件不同
3、sqlSession相同,两次查询之间执行了增删改操作!
4、sqlSession相同,手动清除一级缓存
二级缓存
使用步骤:
1、开启全局缓存 【mybatis-config.xml】
1 <setting name ="cacheEnabled" value ="true" />
2、去每个mapper.xml中配置使用二级缓存,这个配置非常简单;【xxxMapper.xml】
1 2 3 4 5 <cache eviction ="FIFO" flushInterval ="60000" size ="512" readOnly ="true" />
3、代码测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Test public void testQueryUserById () { SqlSession session = MybatisUtils.getSession(); SqlSession session2 = MybatisUtils.getSession(); UserMapper mapper = session.getMapper(UserMapper.class); UserMapper mapper2 = session2.getMapper(UserMapper.class); User user = mapper.queryUserById(1 ); System.out.println(user); session.close(); User user2 = mapper2.queryUserById(1 ); System.out.println(user2); System.out.println(user==user2); session2.close(); }
结论
只要开启了二级缓存,我们在同一个Mapper中的查询,可以在二级缓存中拿到数据
查出的数据都会被默认先放在一级缓存中
只有会话提交或者关闭以后,一级缓存中的数据才会转到二级缓存中
第三方缓存实现——EhCache Ehcache是一种广泛使用的java分布式缓存,用于通用缓存;
要在应用程序中使用Ehcache,需要引入依赖的jar包
1 2 3 4 5 6 <dependency > <groupId > org.mybatis.caches</groupId > <artifactId > mybatis-ehcache</artifactId > <version > 1.1.0</version > </dependency >
在mapper.xml中使用对应的缓存即可
1 2 3 <mapper namespace = “org.acme.FooMapper” > <cache type = “org.mybatis.caches.ehcache.EhcacheCache” /> </mapper >
编写ehcache.xml文件,如果在加载时未找到/ehcache.xml资源或出现问题,则将使用默认配置。
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 <?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 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" /> </ehcache >