一、第一个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 >