前言 终于开始学Mybatis了,其实是javaweb跳的很快,因为air师傅和其他师傅都说过jsp老化了,只需要学习一些原理即可,没必要深究,所以就直接来这了
什么是Mybatis 
Mybatis是一款优秀的持久性框架 
它支持定制化SQL,存储过程以及高级映射 
MYbatis几乎避免了所有JDBC代码和手动设置参数以及获取结果集 
Mybatis可以使用简单的XML或注解来配置和映射原生类型,接口和java的POJO(普通老式java对象)为数据库中的记录 
 
如果获取mybatis :
一句话简单来说,Mybatis就是持久层的框架,也就是和数据库相关的框架 
第一个Mybatis程序 环境搭建->导入Mybatis->编写代码->测试
环境搭建 由于和数据库有关,我们就要搭建一个MYSQL数据库 先创建一个数据库: 新建一个普通的maven项目:
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 <?xml version="1.0"  encoding="UTF-8" ?> <project  xmlns ="http://maven.apache.org/POM/4.0.0"           xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"           xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" >     <modelVersion > 4.0.0</modelVersion >      <groupId > org.example</groupId >      <artifactId > Mybatis</artifactId >      <version > 1.0-SNAPSHOT</version >      <properties >          <maven.compiler.source > 8</maven.compiler.source >          <maven.compiler.target > 8</maven.compiler.target >          <project.build.sourceEncoding > UTF-8</project.build.sourceEncoding >      </properties >      <dependencies >          <dependency >              <groupId > mysql</groupId >              <artifactId > mysql-connector-java</artifactId >              <version > 8.0.30</version >          </dependency >          <dependency >              <groupId > org.mybatis</groupId >              <artifactId > mybatis</artifactId >              <version > 3.5.6</version >          </dependency >          <dependency >              <groupId > junit</groupId >              <artifactId > junit</artifactId >              <version > 4.13.1</version >          </dependency >      </dependencies >  </project > 
 
记得把src文件夹删了,作为父工程
创建一个模块(maven项目)  这样每次子项目就不需要导包,方便很多 配置mybatis的核心配置文件:
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" > </transactionManager >              <dataSource  type ="POOLED" >                  <property  name ="driver"  value ="com.mysql.cj.jdbc.Driver" > </property >                  <property  name ="url"  value ="jdbc:mysql://localhost:3306/mybatis?useSSL=true& useUnicode=true& characterEncoding=UTF-8" > </property >                  <property  name ="username"  value ="root" > </property >                  <property  name ="password"  value ="jiayou357753" > </property >              </dataSource >          </environment >      </environments >      <mappers >          <mapper  resource ="com/kino/dao/UserDao.xml" />      </mappers >  </configuration > 
 
其中<environment id="development">表示环境的ID,可以有多个测试环境,然后上面一个标签有 <environments default="development">就是默认的测试环境
<property name="url" value="${jdbc.url}"></property>: 是我们jdbc的url:jdbc:mysql://localhost:3306
1 2 3 4 <property name="driver" value="${jdbc.driver}"></property> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"></property> <property name="username" value="root"></property> <property name="password" value="jiayou357753"></property> 
 
URL一栏多了一些参数,分别是安全连接和编码
从 XML 中构建 SqlSessionFactory 
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。 从 XML 文件中构建 SqlSessionFactory 的实例非常简单,建议使用类路径下的资源文件进行配置。 但也可以使用任意的输入流(InputStream)实例,比如用文件路径字符串或 file:// URL 构造的输入流。MyBatis 包含一个名叫 Resources 的工具类,它包含一些实用方法,使得从类路径或其它位置加载资源文件更加容易。
 
1 2 3 String resource = "org/mybatis/example/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 
 
从 SqlSessionFactory 中获取 SqlSession 既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。例如:
1 2 3 try (SqlSession session = sqlSessionFactory.openSession()) {   Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101); } 
 
诚然,这种方式能够正常工作,对使用旧版本 MyBatis 的用户来说也比较熟悉。但现在有了一种更简洁的方式——使用和指定语句的参数和返回值相匹配的接口(比如 BlogMapper.class),现在你的代码不仅更清晰,更加类型安全,还不用担心可能出错的字符串字面值以及强制类型转换。 例如:
1 2 3 4 try (SqlSession session = sqlSessionFactory.openSession()) {   BlogMapper mapper = session.getMapper(BlogMapper.class);   Blog blog = mapper.selectBlog(101); } 
 
编写一个工具类 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.Boogipop.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  MybatisUtil  {    private  static  SqlSessionFactory sqlSessionFactory;         static  {         try  {                          String  resource  =  "mybatis-config.xml" ;             InputStream  inputStream  =  Resources.getResourceAsStream(resource);             SqlSessionFactory  sqlSessionFactory  =  new  SqlSessionFactoryBuilder ().build(inputStream);         } catch  (IOException e) {             throw  new  RuntimeException (e);         }     }          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 package  com.Boogipop.pojo;public  class  User  {    private  int  id;     private  String name;     private  String pwd;     public  void  setId (int  id)  {         this .id = id;     }     public  void  setName (String name)  {         this .name = name;     }     public  void  setPwd (String pwd)  {         this .pwd = pwd;     }     public  int  getId ()  {         return  id;     }     public  String getName ()  {         return  name;     }     public  String getPwd ()  {         return  pwd;     }     public  User (int  id, String name, String pwd)  {         this .id = id;         this .name = name;         this .pwd = pwd;     } } 
 
Dao类(操作实体类的接口) 1 2 3 4 5 6 7 8 9 10 package  com.Boogipop.dao;import  com.Boogipop.pojo.User;import  java.util.List;public  interface  UserDao  {    List<User> getuserlist () ; } 
 
接口实现类 这里就省去了JDBC对结果集的处理的繁琐过程了,体现Mybatis的优势 由原来的implement改为了一个mapper
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package  com.Boogipop.dao;import  com.Boogipop.pojo.User;import  java.util.List;public  class  UserDaoImp   implements  UserDao {    @Override      public  List<User> getuserlist ()  {         String sql=""      } } 
 
上面是原来的,下面是mybatis的处理方法
1 2 3 4 5 6 7 8 9 10 11 12 13 <?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 /> <mapper  namespace ="com.Boogipop.dao.UserDao" > <select  id ="getuserlist"  resultType ="com.Boogipop.pojo.User" > -- resulttype是返回结果类型     select * from User </select > </mapper > 
 
 napespace就是Dao接口,resultType就是定义的要查询的sql对象类 这边select的id切记和之前的dao(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 package  com.Boogipop.dao;import  com.Boogipop.pojo.User;import  com.Boogipop.utils.MybatisUtil;import  org.apache.ibatis.session.SqlSession;import  org.junit.Test;import  java.util.List;public  class  UserDaotest  {    @Test      public  void  test () {                  SqlSession  sqlsession  =  MybatisUtil.getSqlsession();                  UserDao  mapper  =  sqlsession.getMapper(UserDao.class);         List<User> getuserlist = mapper.getuserlist();         for  (User user : getuserlist) {             System.out.println(user);         }                  sqlsession.close();     } } 
 
运行过后会报错: 因为在刚开始创建mybatis-config.xml中没注册mapper: 之后又会报错初始化异常: 这是当时在Maven里讲的,由于maven约定大于配置,所以会产生配置文件无法生效的问题,解决方案就是在pom.xml(主工程和子工程)里添加:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <build >     <resources >          <resource >              <directory > src/main/resources</directory >              <includes >                  <include > **/*.properties</include >                  <include > **/*.xml</include >              </includes >          </resource >          <resource >              <directory > src/main/java</directory >              <includes >                  <include > **/*.properties</include >                  <include > **/*.xml</include >              </includes >              <filtering > true</filtering >          </resource >      </resources >  </build > 
 
错误总结(续上面) 然后还会有几个几把错误,希望不要再犯,首先一定要检查你的mybatis-config.xml是否配置正确,其次就是上面说的maven约定大于配置的问题(还有其他解决方法,例如直接把xml配置文件放到resource文件夹,因为resource文件夹是默认配置目录) 最后是弃用方法要省略<property name="driver" value="com.mysql.cj.jdbc.Driver"></property> 这是mybatis-config.xml配置文件中的一句话,之前是没有cj的,最后也是可以如愿得到运行结果(呼!) 给折磨坏了
测试类里执行sql第二种方法(推荐) 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 package  com.kino.dao;import  com.kino.pojo.User;import  com.kino.utils.MybatisUtil;import  org.apache.ibatis.session.SqlSession;import  org.junit.Test;import  java.util.List;public  class  UserDaotest  {    @Test      public  void  test () {                  SqlSession  sqlsession  =  MybatisUtil.getSqlsession();                  UserDao  mapper  =  sqlsession.getMapper(UserDao.class);         List<User> list = sqlsession.selectList("com.kino.dao.UserDao.getuserlist" );         for  (User user : list) {             System.out.println(user);         }                  sqlsession.close();     } } 
 
他奶奶的第一集一个小时,我真的是日了狗了,之后再消化一下
增删改查实现(CURD) namespace(命名空间) namespace中的包名要和接口的包名一致 上面我用的是UserDao,但这次我改了个名字UserMapper:
select 查询语句嘛,我们在写UserMapper.xml的时候有个select标签,里面有几个属性
id: 对应的就是接口中的方法名称(等效于JDBC中的实现接口) 
resultType: sql执行语句的返回值类型 
parameterType:参数类型 
 
parameterType怎么用,我们写一个根据id返回结果的小Demo来学习
1 User getuserbyid (int  id) ; 
 
在这一步定义了一个接口有参方法,里面传入的形参就是我们的id
1 2 3 4 5 6 7 8 9 10 11 12 13 <?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.kino.dao.UserMapper" > <select  id ="getuserlist"  resultType ="com.kino.pojo.User" >     select * from user </select >     <select  id ="getuserbyid"  resultType ="com.kino.pojo.User"  parameterType ="int" >          select * from user where id=#{id}     </select >  </mapper > 
 
Mapper.xml也添加相应的select标签和语句,这里的select标签的parameterType就是int,然后#{id}就表示我们自定义的id,这是一个语法,用#{}去包裹我们需要传入的参数,这里的#{id}看起来和上面的形参id名称一样,实际上可以不一样,你可以#{id2}、#{number}等等,他也算一个形参 最后再写一个测试方法:
1 2 3 4 5 6 7 8 9 @Test   public  void  getuserbyid () {       SqlSession sqlSession=MybatisUtil.getSqlsession();       UserMapper  mapper  =  sqlSession.getMapper(UserMapper.class);       User  user  =  mapper.getuserbyid(1 );       System.out.println(user);       sqlSession.close();   } 
 
insert 1 2 3 4 5 6 7 8 9 10 11 12 13 14 package  com.kino.dao;import  com.kino.pojo.User;import  java.util.List;public  interface  UserMapper  {    List<User> getuserlist () ;          User getuserbyid (int  id) ;          Boolean adduser (User user) ; } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?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.kino.dao.UserMapper" >     <select  id ="getuserlist"  resultType ="com.kino.pojo.User" >          select * from user     </select >           <select  id ="getuserbyid"  resultType ="com.kino.pojo.User"  parameterType ="int" >          select * from user where id=#{id}     </select >      <insert  id ="adduser"  parameterType ="com.kino.pojo.User" >          insert into mybatis.user(id,name,pwd) values(#{id},#{name},#{pwd});     </insert >  </mapper > 
 
语法后的分号可有可不有
1 2 3 4 5 6 7 8 9 10 public  void  adduser () {    SqlSession sqlSession=MybatisUtil.getSqlsession();     UserMapper  mapper  =  sqlSession.getMapper(UserMapper.class);     Boolean  adduser  =  mapper.adduser(new  User (3 , "Boogipop2" , "2662501" ));     if  (adduser){         System.out.println("添加成功" );     }     sqlSession.commit();      sqlSession.close(); } 
 
 添加成功了
delete 和insert也是一个思路
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package  com.kino.dao;import  com.kino.pojo.User;import  java.util.List;public  interface  UserMapper  {    List<User> getuserlist () ;          User getuserbyid (int  id) ;          Boolean adduser (User user) ;          Boolean deluser (int  id) ; } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?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.kino.dao.UserMapper" >     <select  id ="getuserlist"  resultType ="com.kino.pojo.User" >          select * from user     </select >           <select  id ="getuserbyid"  resultType ="com.kino.pojo.User"  parameterType ="int" >          select * from user where id=#{id}     </select >      <insert  id ="adduser"  parameterType ="com.kino.pojo.User" >          insert into mybatis.user(id,name,pwd) values(#{id},#{name},#{pwd});     </insert >      <delete  id ="deluser"  parameterType ="int" >          delete from user where id=#{id}     </delete >  </mapper > 
 
1 2 3 4 5 6 7 8 9 10 11 @Test   public  void  deluser () {       SqlSession sqlSession=MybatisUtil.getSqlsession();       UserMapper  mapper  =  sqlSession.getMapper(UserMapper.class);       Boolean deluser=mapper.deluser(3 );       if (deluser){           System.out.println("删除成功" );       }       sqlSession.commit();       sqlSession.close();   } 
 
 ,最后也是删除成功了
update 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package  com.kino.dao;import  com.kino.pojo.User;import  java.util.List;public  interface  UserMapper  {    List<User> getuserlist () ;          User getuserbyid (int  id) ;          Boolean adduser (User user) ;          Boolean deluser (int  id) ;          Boolean cguser (User user) ; } 
 
1 2 3 <update id="cguser"  parameterType="com.kino.pojo.User" >        update user set name=#{name},pwd=#{pwd} where id=#{id}    </update> 
 
这里#{}中的内容一定要和类中定义的名字一样
1 2 3 4 5 6 7 8 9 10 11 @Test    public  void  cguser () {        SqlSession sqlSession=MybatisUtil.getSqlsession();        UserMapper  mapper  =  sqlSession.getMapper(UserMapper.class);        Boolean cguser=mapper.cguser(new  User (1 ,"Kino2!" ,"asdasdasd" ));        if (cguser){            System.out.println("更新成功" );        }        sqlSession.commit();        sqlSession.close();    } 
 
 也是修改成功
错误排查 
UserMapper.xml中不要出现什么语法错误,对应的namespace和id等等属性对应好 
 
一句话说就是自己排查错误
Map和模糊查询 细心一点的人就发现了,假如每次参数类型都是User,咱们就不好去指定需要插入的数据或者是删除的数据。Map集合就可以很好解决这一点问题 接下来就写个小demo,用Map来添加数据
1 Boolean mapadduser (Map<String,Object> map) ; 
 
1 2 3 <insert  id ="mapadduser"  parameterType ="Map" >     insert into user(id,name) values(#{id},#{name}) </insert > 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Test public  void  mapadduser () {    SqlSession sqlSession=MybatisUtil.getSqlsession();     UserMapper  mapper  =  sqlSession.getMapper(UserMapper.class);     HashMap<String, Object> map=new  HashMap <>();     map.put("id" ,"3" );     map.put("name" ,"asdas5da65s" );     Boolean  mapadduser  =  mapper.mapadduser(map);     if (mapadduser){         System.out.println("添加成功" );     }     sqlSession.commit();     sqlSession.close(); } 
 
 添加成功了,这边Map的键要和我们的字段名称一一对应,否则会出现为null的情况
接下来就是如何使用mybatis进行模糊查询,也就是like语句的使用,并且不留SQL注入隐患
1 User getuserbylike (Map<String,Object> map) ; 
 
1 2 3 <select  id ="getuserbylike"  parameterType ="Map"  resultType ="com.kino.pojo.User" >   select * from user where name like concat("%",#{name},"%") </select > 
 
1 2 3 4 5 6 7 8 9 10 @Test  public  void  selectbylike () {      SqlSession sqlSession=MybatisUtil.getSqlsession();      UserMapper  mapper  =  sqlSession.getMapper(UserMapper.class);      HashMap<String,Object> hashMap=new  HashMap <>();      hashMap.put("name" ,"B" );      User  getuserbylike  =  mapper.getuserbylike(hashMap);      System.out.println(getuserbylike);      sqlSession.close();  } 
 

 
注意XML中我用了concat,这样可以从一定程度避免sql注入
配置优化——属性  mybatis核心配置文件如上,我们environment和mappers我们都用过了,这里介绍一下属性properties 首先先回顾一下environments:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <environments  default ="development" >         <environment  id ="development" >              <transactionManager  type ="JDBC" > </transactionManager >              <dataSource  type ="POOLED" >                  <property  name ="driver"  value ="com.mysql.cj.jdbc.Driver" > </property >                  <property  name ="url"  value ="jdbc:mysql://localhost:3306/mybatis?useSSL=true& useUnicode=true& characterEncoding=UTF-8" > </property >                  <property  name ="username"  value ="root" > </property >                  <property  name ="password"  value ="jiayou357753" > </property >              </dataSource >          </environment >          <environment  id ="test" >                  <transactionManager  type ="JDBC" > </transactionManager >                  <dataSource  type ="POOLED" >                      <property  name ="driver"  value ="com.mysql.cj.jdbc.Driver" > </property >                      <property  name ="url"  value ="jdbc:mysql://localhost:3306/mybatis?useSSL=true& useUnicode=true& characterEncoding=UTF-8" > </property >                      <property  name ="username"  value ="root" > </property >                      <property  name ="password"  value ="jiayou357753" > </property >                  </dataSource >              </environment >      </environments >  
 
上面部分核心配置文件中,有2个environment,我们假如想要切换,只需修改default标签为对应的id即可
transactionManager标签也就是事务管理器,有JDBC和MANAGED两种方式,但是MANAGED我们已经不再用了 
dataSource标签表示数据源,如dbcp、c3p0、druid、JNDI 
 
在mybatis中自带3种内置数据源类型JNDI,UNPOOLED,POOLED,POOL也就是池的意思,代表能否复用的意思(用完了换个进程继续用),UNPOOLED也就是没有池的概念,因此性能要求不高mybatis可以配置成适应多种环境,但是SqlsessionFactory只能用一种  mybatis的默认事务处理器是JDBC,连接池是POOLED
properties属性 可以用来引入.properties配置文件,也可以在标签中自己添加属性和数值
1 2 3 4 driver=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&seUnicode=true&characterEncoding=UTF-8 username=root password=jiayou357753 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?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 >     <properties  resource ="db.properties" >          <property  name ="useless"  value ="useless" />      </properties >      <environments  default ="development" >          <environment  id ="development" >              <transactionManager  type ="JDBC" > </transactionManager >              <dataSource  type ="POOLED" >                  <property  name ="driver"  value ="${driver}" > </property >                  <property  name ="url"  value ="${url}" > </property >                  <property  name ="username"  value ="${username}" > </property >                  <property  name ="password"  value ="${password}" > </property >              </dataSource >          </environment >      </environments >      <mappers >          <mapper  resource ="com/kino/dao/UserMapper.xml" />      </mappers >  </configuration > 
 
${}:和#{}一样也是一种占位符
别名配置优化 方案一 在mybatis-config.xml有个tag叫做<typeAliases>,它用来对我们的类设置别名,比如我们再Usermapper.xml中,设置resultType每次都是com.kino.pojo.User 每次都要写这么长就很繁琐,因此可以设置别名:
1 2 3 <typeAliases >         <typeAlias  type ="com.kino.pojo.User"  alias ="User" />      </typeAliases > 	 
 
mybatis核心配置文件内,这些标签有顺序的,这个需要写在properties标签下,这里需要注意 标签顺序如上 配置过后就可以把UserMapper.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 <?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.kino.dao.UserMapper" >     <select  id ="getuserlist"  resultType ="com.kino.pojo.User" >          select * from user     </select >           <select  id ="getuserbyid"  resultType ="User"  parameterType ="int" >          select * from user where id=#{id}     </select >      <insert  id ="adduser"  parameterType ="User" >          insert into mybatis.user(id,name,pwd) values(#{id},#{name},#{pwd});     </insert >      <delete  id ="deluser"  parameterType ="int" >          delete from user where id=#{id}     </delete >      <update  id ="cguser"  parameterType ="User" >          update user set name=#{name},pwd=#{pwd} where id=#{id}     </update >      <insert  id ="mapadduser"  parameterType ="Map" >          insert into user(id,name) values(#{id},#{name})     </insert >      <select  id ="getuserbylike"  parameterType ="Map"  resultType ="User" >          select * from user where name like concat("%",#{name},"%")     </select >  </mapper > 
 
运行test类看看结果是否正常: 结果正常说明配置生效
方案二 还有一种写法
1 2 3 <typeAliases >       <package  name ="com.kino.pojo" />    </typeAliases >  
 
这样的写法默认会讲com.kino.pojo下的类别名设置为类名的小写形式,如User的别名就是user 当然我们可以通过注解自定义别名: 测试一下是否正常运行 运行正常
这两种的适用的场合也就是你需要别名的类是否很多,如果很多的话就用方案二的package,很少就用方案一吧,我个人是倾向于方案二的
映射器配置 映射器已经见得多了,就是mybatis核心配置文件中注册我们mapper的标签 它有如下三种写法:
1 2 3 4 <mappers >   <mapper  resource ="com/kino/dao/UserMapper.xml" />  </mappers > 
 
1 2 3 4 <mappers >   <mapper  class ="com.kino.dao.UserMapper" />  </mappers > 
 
1 2 3 4 <mappers >   <mapper  url ="file:///var/mappers/AuthorMapper.xml" />  </mappers > 
 
1 2 3 4 <mappers >   <package  name ="org.mybatis.builder" />  </mappers > 
 
以上四种用法结合实际情况去使用
作用域(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()) {   } 
 
可以将SqlSessionFactory理解为一个线程池,然后SqlSession用来连接线程池,因此当SqlSession结束了事务后,要关闭SqlSession避免占用
ResultMap结果集映射 我们如何利用ResultMap结果映射集去解决pojo中类属性名称和数据库中字段名称不一致的问题呢,针对这个问题其实有两种解法,分别从数据库和mybatis方向去解决
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 package  com.kino.pojo;import  org.apache.ibatis.type.Alias;@Alias("User") public  class  User  {    private  int  id;     private  String name;     private  String password;     @Override      public  String toString ()  {         return  "User{"  +                 "id="  + id +                 ", name='"  + name + '\''  +                 ", password='"  + password + '\''  +                 '}' ;     }     public  void  setId (int  id)  {         this .id = id;     }     public  void  setName (String name)  {         this .name = name;     }     public  void  setPassword (String password)  {         this .password = password;     }     public  int  getId ()  {         return  id;     }     public  String getName ()  {         return  name;     }     public  String getPassword ()  {         return  password;     }     public  User () {     } } 
 
注意这里我用了无参构造方法啊,这里的坑后面会讲  这样查出来的password为空
方案1——使用as别名 将select * from user改为select id,name,pwd as password from user即可
方案2(推荐)——使用ResultMap映射  这是官方文档的用法,但是看官方文档总是会有种不说人话的感觉 我们将我们的UserMapper文件改为:
1 2 3 4 5 6 7 <resultMap  id ="Anything"  type ="User" >        <result  property ="password"  column ="pwd" />      </resultMap >         <select  id ="getuserbyid"  resultMap ="Anything"  parameterType ="int" >         select * from user where id=#{id}    </select >  
 
将结果设为resultMap,名称自定义,但是要与上面的resultMap标签的id属性对应,这就是设置一个映射关系,同样的结果也能显示出来
填坑 回来填坑,为什么要用无参的构造方法呢,因为经过我的测试,假如你的构造器是有参构造器,不管你字段名和属性对不对应结果都会返回结果 这边猜测是mybatis处理结果时,会优先使用有参构造函数去返回结果的User类,这就是一个自动对应 假如用无参构造方法的话,就只能更改属性了,因此就没有对应关系 纯属个人猜测
日志工厂 在mybatis中由于简化jdbc事务,因此不能直接使用out去输出运行的Sql语句,由此日志工厂诞生了: mybatis中默认不开启日志事务,因此需要手动添加配置
默认日志 1 2 3 4 <settings >         <setting  name ="logImpl"  value ="STDOUT_LOGGING" />      </settings >  
 
配置好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 Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter. Class not found: org.jboss.vfs.VFS JBoss 6 VFS API is not available in this environment. Class not found: org.jboss.vfs.VirtualFile VFS implementation org.apache.ibatis.io.JBoss6VFS is not valid in this environment. Using VFS adapter org.apache.ibatis.io.DefaultVFS Find JAR URL: file:/E:/CTF%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0/Mybatis/Mybatis/mabtis-01/target/classes/com/kino/pojo Not a JAR: file:/E:/CTF%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0/Mybatis/Mybatis/mabtis-01/target/classes/com/kino/pojo Reader entry: User.class Listing file:/E:/CTF%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0/Mybatis/Mybatis/mabtis-01/target/classes/com/kino/pojo Find JAR URL: file:/E:/CTF%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0/Mybatis/Mybatis/mabtis-01/target/classes/com/kino/pojo/User.class Not a JAR: file:/E:/CTF%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0/Mybatis/Mybatis/mabtis-01/target/classes/com/kino/pojo/User.class Reader entry: ����   4 @ - Checking to see if class com.kino.pojo.User matches criteria [is assignable to Object] PooledDataSource forcefully closed/removed all connections. PooledDataSource forcefully closed/removed all connections. PooledDataSource forcefully closed/removed all connections. PooledDataSource forcefully closed/removed all connections. Opening JDBC Connection Created connection 1380806038. Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@524d6d96] ==>  Preparing: select * from user ==> Parameters:  <==    Columns: id, name, pwd <==        Row: 1, Kino!, asdasdasd <==        Row: 2, boogipop, admin <==        Row: 3, Boogipop2, 2662501 <==        Row: 4, Boogipop4, 2662501 <==        Row: 4, Boogipop4, 2662501 <==        Row: 4, Boogipop4, 2662501 <==      Total: 6 User{id=1, name='Kino!', pwd='asdasdasd'} User{id=2, name='boogipop', pwd='admin'} User{id=3, name='Boogipop2', pwd='2662501'} User{id=4, name='Boogipop4', pwd='2662501'} User{id=4, name='Boogipop4', pwd='2662501'} User{id=4, name='Boogipop4', pwd='2662501'} Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@524d6d96] Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@524d6d96] Returned connection 1380806038 to pool. Process finished with exit code 0 
 
我们的SQL执行语句已经在上面给显示出来了
LOG4J2 https://www.jianshu.com/p/c6c543e4975e  配置文件之类的参考如上: LOG4J漏洞百出,现在用的都是2 先安装Maven依赖:
1 2 3 4 5 6 7 8 9 10 <dependency >     <groupId > org.apache.logging.log4j</groupId >      <artifactId > log4j-slf4j-impl</artifactId >      <version > 2.19.0</version >  </dependency > <dependency >     <groupId > org.apache.logging.log4j</groupId >      <artifactId > log4j-core</artifactId >      <version > 2.19.0</version >  </dependency > 
 
之后再mybatis核心配置文件中的settings设置一下logImpl的种类为LOG4J2:
1 2 3 <settings >         <setting  name ="logImpl"  value ="LOG4J2" />      </settings >  
 
之后只需要设置一下log4j2的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 <?xml version="1.0"  encoding="UTF-8" ?> <Configuration  status ="TRACE" >          <Appenders >                   <Console  name ="Console"  target ="SYSTEM_OUT" >                           <PatternLayout                       pattern ="%d{HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"  />             "/>         </Console >                   <File  name ="MyFile"  fileName ="./logs/info.log"  append ="true" >              <PatternLayout >                                   <pattern > %d{HH:mm:ss} [%t] %-5level %logger{36} - %msg%n</pattern >              </PatternLayout >          </File >      </Appenders >           <Loggers >                   <logger  name ="com.kino.dao.UserMapper"  level ="TRACE"                   additivity ="false" >             <AppenderRef  ref ="Console"  />              <AppenderRef  ref ="MyFile"  />          </logger >          <Root  level ="info" >              <AppenderRef  ref ="Console"  />              <AppenderRef  ref ="MyFile"  />          </Root >      </Loggers >  </Configuration > 
 
 这样日志文件就会在控制台和文件中输出
然后同时我们也可以在我们的测试类中使用LOG4J2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 static  Logger logger=LogManager.getLogger();    @Test      public  void  test () {                  SqlSession  sqlsession  =  MybatisUtil.getSqlsession();                  UserMapper  mapper  =  sqlsession.getMapper(UserMapper.class);         logger.info("=====info信息开始=====" );         List<User> getuserlist = mapper.getuserlist();         for  (User user : getuserlist) {             System.out.println(user);         }         sqlsession.close();     } 
 
 用法大概就这样拉QWQ
Limit实现分页 使用limit 就普通SQL的limit语法
使用RowBounds  大概就如上的用法,通过代码层面来实现分页,其实没啥东西
使用注解进行开发 上述我们进行的操作都是通过接口和xml文件进行的,现在来说一下如何直接利用注解来执行SQL语句:
1 2 3 4 5 6 7 8 9 10 11 12 13 package  com.boogipop.dao;import  com.boogipop.pojo.User;import  org.apache.ibatis.annotations.Select;import  java.util.List;public  interface  UserMapper  {    @Select("select * from user")      List<User> getuserlist () ;      } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 package  com.boogipop.dao;import  com.boogipop.pojo.User;import  org.apache.ibatis.annotations.Select;import  java.util.List;public  interface  UserMapper  {    @Select("select * from user")      List<User> getuserlist () ;      } 
 
1 2 3 <mappers>         <mapper class="com.boogipop.dao.UserMapper" />     </mappers> 
 
核心配置文件中关于mappers的映射就要改为class了 结果是能正常输出,但是password为null,这是因为字段和属性名称不对应,所以假如用注解去执行SQL的时候就切记一定要对应起来,否则就null了 下个断点调试其实可以发现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 package  com.boogipop.dao;import  com.boogipop.pojo.User;import  org.apache.ibatis.annotations.*;import  java.util.HashSet;import  java.util.List;public  interface  UserMapper  {    @Select("select * from user")      List<User> getuserlist () ;     @Insert("insert into user(id,name,pwd) values(#{id},#{name},#{password})")      Boolean adduser (User user) ;     @Update("update user set name=#{name},pwd=#{password} where id=#{id}")      Boolean updateuser (User user) ;     @Delete("delete from user where id=#{id}")           Boolean deleteuser (@Param("id")  int  id) ;     @Select("select * from user where name=#{name}")      HashSet<User> getuserbyname (@Param("name")  String name) ; } 
 
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 57 58 59 60 61 62 63 64 65 66 67 68 package  com.boogipop.dao;import  com.boogipop.pojo.User;import  com.boogipop.utils.MybatisUtil;import  org.apache.ibatis.session.SqlSession;import  org.junit.Test;import  java.util.HashSet;import  java.util.List;public  class  UserDaotest  {    @Test      public  void  select () {                  SqlSession  sqlsession  =  MybatisUtil.getSqlsession();                  UserMapper  mapper  =  sqlsession.getMapper(UserMapper.class);         List<User> getuserlist = mapper.getuserlist();         for  (User user : getuserlist) {             System.out.println(user);         }         sqlsession.close();     }     @Test      public  void  adduser () {         SqlSession  sqlsession  =  MybatisUtil.getSqlsession();                  UserMapper  mapper  =  sqlsession.getMapper(UserMapper.class);         User user=new  User (5 ,"ass" ,"123" );         Boolean  adduser  =  mapper.adduser(user);         if  (adduser){             System.out.println("Add successfully!" );         }         sqlsession.close();     }     @Test      public  void  updateuse () {         SqlSession sqlSession=MybatisUtil.getSqlsession();         UserMapper mapper=sqlSession.getMapper(UserMapper.class);         User user=new  User (3 ,"Jack" ,"sada123sdd2!" );         Boolean  updateuser  =  mapper.updateuser(user);         if (updateuser){             System.out.println("update successfully" );         }         sqlSession.close();     }     @Test      public  void  deleteuser () {         SqlSession sqlSession=MybatisUtil.getSqlsession();         UserMapper mapper=sqlSession.getMapper(UserMapper.class);         Boolean  deleteuser  =  mapper.deleteuser(4 );         if (deleteuser){             System.out.println("delete successfully" );         }         sqlSession.close();     }     @Test      public  void  getbyid () {         SqlSession sqlSession=MybatisUtil.getSqlsession();         UserMapper userMapper=sqlSession.getMapper(UserMapper.class);         HashSet<User> boogipop = userMapper.getuserbyname("boogipop" );         for  (User user : boogipop) {             System.out.println(user);         }         sqlSession.close();     } } 
 
当参数为基本类型时需要用param去强调,是引用类型的时候就免了,另外注意param参数对应的问题 然后这里大家可能发现我没提交事务,因为我改了一下工具类: 我传了一个ture进去就代表会自动提交,默认为false
mybatis执行流程 这个我们已经有了一个总体的认知,mybatis其实就是对底层jdbc的一个包装 不细讲 SqlSessionFactoryBuilder->inputStream->得到xml配置->sqlSessionFactory->transaction事务管理->excutor执行器->得到Sqlsession
Lombok简化 啥是lombok呢,我们创建一个类可以用alt+insert去添加一些常用方法 而lombok直接就更加简化了这些步骤,首先在settings里的plugins中安装lombok插件,然后再导入maven依赖:
1 2 3 4 5 6 7 <dependencies >     <dependency >          <groupId > org.projectlombok</groupId >          <artifactId > lombok</artifactId >          <version > 1.18.24</version >      </dependency >  </dependencies > 
 
包含所有参数的构造方法
无参构造方法
这些注解会自动帮你添加这些方法,就挺方便
复杂查询模式环境搭建 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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, 'Boogipop');  CREATE TABLE `student` (   `id` INT(10) NOT NULL,   `name` VARCHAR(30) DEFAULT NULL,   `tid` INT(10) DEFAULT NULL,   PRIMARY KEY (`id`),   CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`) ) ENGINE=INNODB DEFAULT CHARSET=utf8 INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', 'Kino', '1');  INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', 'Jack', '1');  INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', 'Benk', '1');  INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', 'Siri', '1');  INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', 'Benk', '1'); 
 
首先先在本地SQL创建一下表,这里其实对KEY这个概念有点生疏,PRIMARY KEY表示主键,FOREIGN KEY表示外键,用来把本表字段和其他表字段做一个约束:https://www.jianshu.com/p/010106e61cc6  在这里对student表创建了主键id,不准有重复的列、不能有NULL值,每个表只有一个主键 这样表就构造好了,接下来要做的是在Mybatis中去处理这种关联关系,在这里一个老师对应多个学生 先新建一个mybatis子项目,然后把pojo和dao啥的翻一番:
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 <?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 >     <properties  resource ="db.properties" >          <property  name ="useless"  value ="useless" />      </properties >      <settings >          <setting  name ="logImpl"  value ="STDOUT_LOGGING" />      </settings >      <typeAliases >          <package  name ="com.mybatis3.pojo" />      </typeAliases >      <environments  default ="development" >          <environment  id ="development" >              <transactionManager  type ="JDBC" > </transactionManager >              <dataSource  type ="POOLED" >                  <property  name ="driver"  value ="${driver}" > </property >                  <property  name ="url"  value ="${url}" > </property >                  <property  name ="username"  value ="${username}" > </property >                  <property  name ="password"  value ="${password}" > </property >              </dataSource >          </environment >      </environments >      <mappers >          <mapper  resource ="StudentMapper.xml" />      </mappers >  </configuration > 
 
1 2 3 4 5 6 7 8 9 <?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.mybatis3.dao.StudentMapper" >     <select  id ="getstudentlist"  resultType ="Student" >          select * from student     </select >  </mapper > 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package  com.mybatis3.pojo;import  lombok.Data;import  org.apache.ibatis.type.Alias;@Data @Alias("Student") public  class  Student  {    private  int  id;     private  String name;     private  int  tid;     private  Teacher teacher; } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import  com.mybatis3.dao.StudentMapper;import  com.mybatis3.pojo.Student;import  com.mybatis3.utils.MybatisUtil;import  org.apache.ibatis.session.SqlSession;import  org.junit.Test;import  java.util.List;public  class  Excute  {    @Test      public  void  getstudent () {         SqlSession sqlSession= MybatisUtil.getSqlsession();         StudentMapper mapper=sqlSession.getMapper(StudentMapper.class);         List<Student> getstudentlist = mapper.getstudentlist();         for  (Student student : getstudentlist) {             System.out.println(student);         }         sqlSession.close();     } } 
 
1 2 3 4 5 6 7 8 9 10 package  com.mybatis3.dao;import  com.mybatis3.pojo.Student;import  java.util.List;public  interface  StudentMapper  {    List<Student> getstudentlist () ; } 
 
这样就可以正常得到我们的测试结果: 因为返回值里没teacher所以为false 然后由于我们设置了主键,所以现在就有个非常有意思是的现象: 主键不能重复 而且我们添加数据的时候会自动帮我们加上id: 挺方便的,所以在创建SQL的时候记得加个主键约束
多对一处理 现在我们要完成一个需求,搜索学生的时候,顺便把和tid绑定的teacher的信息一起输出出来。
查询进行嵌套 1 List<Student> getteacherlist (); 
 
1 2 3 4 5 6 <select  id ="selectall"  resultMap ="all" >         select * from student     </select >      <resultMap  id ="all"  type ="Student" >          <association  property ="teacher"  column ="tid"  javaType ="Teacher"  select ="getteacherlist" />      </resultMap >  
 
1 2 3 4 5 6 7 8 9 public  void  selectall () {       SqlSession sqlSession= MybatisUtil.getSqlsession();        StudentMapper mapper=sqlSession.getMapper(StudentMapper.class);        List<Student> selectall = mapper.selectall();        for  (Student student : selectall) {            System.out.println(student);        }        sqlSession.close();    } 
 
 可以看到teacher也跟着被输出了,这里的意思其实是tid和getteacherlist接口绑定了
结果进行嵌套 1 2 3 4 5 6 7 8 9 10 11 <select  id ="selectall2"  resultMap ="all2" >        select s.id sid,s.name sname,s.tid tid,t.name tname from student s join teacher t on s.tid=t.id    </select >     <resultMap  id ="all2"  type ="Student" >         <result  property ="tid"  column ="tid" />         <result  property ="name"  column ="sname" />         <result  column ="sid"  property ="id" />         <association  property ="teacher"  javaType ="Teacher" >             <result  column ="tname"  property ="name" />         </association >     </resultMap >  
 
1 2 3 4 5 6 7 8 9 public  void  selectall2 () {       SqlSession sqlSession= MybatisUtil.getSqlsession();        StudentMapper mapper=sqlSession.getMapper(StudentMapper.class);        List<Student> selectall = mapper.selectall2();        for  (Student student : selectall) {            System.out.println(student);        }        sqlSession.close();    } 
 
 teacher中的id为0是因为我们没有选择t.id
一对多处理 昨天讲了多对一,今天将一对多,多对一使用了association标签,而一对多使用collenction标签,都是对应起来的 在实验之前先建一个新的mybatis项目
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package  com.mybatis3.pojo;import  lombok.Data;import  org.apache.ibatis.type.Alias;import  java.util.List;@Data @Alias("Teacher") public  class  Teacher  {    private  int  id;     private  String name;     List<Student> students; } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 package  com.mybatis3.pojo;import  lombok.Data;import  org.apache.ibatis.type.Alias;@Data @Alias("Student") public  class  Student  {    private  int  id;     private  String name;     private  int  tid; } 
 
这次两个pojo类反过来了,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 <?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.mybatis3.dao.StudentMapper" >     <select  id ="getstudentlist"  resultType ="Student" >          select * from student where tid=#{tid}     </select >      <insert  id ="add"  parameterType ="Student" >          insert into student(id,name) values (#{id},#{name})     </insert >      <select  id ="getteacherlist"  resultType ="Teacher" >          select * from teacher     </select >      <select  id ="selectall"  resultMap ="all" >          select * from teacher     </select >      <resultMap  id ="all"  type ="Teacher" >          <result  property ="id"  column ="id" />          <collection  property ="students"  ofType ="Student"  column ="id"  select ="getstudentlist" > </collection >      </resultMap >      <select  id ="selectall2"  resultMap ="all2" >              select * from teacher where id=#{id}     </select >      <resultMap  id ="all2"  type ="Teacher" >          <result  column ="id"  property ="id" />          <result  column ="name"  property ="name" />          <collection  property ="students"  ofType ="Student" >              <result  column ="id"  property ="id" />              <result  column ="name"  property ="name" />              <result  column ="tid"  property ="tid" />          </collection >      </resultMap >  </mapper > 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package  com.mybatis3.dao;import  com.mybatis3.pojo.Student;import  com.mybatis3.pojo.Teacher;import  java.util.List;public  interface  StudentMapper  {    List<Student> getstudentlist (int  tid) ;     Boolean add (Student student) ;     List<Teacher> getteacherlist () ;     List<Teacher> selectall () ;     List<Teacher> selectall2 (int  id) ; } 
 
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 import  com.mybatis3.dao.StudentMapper;import  com.mybatis3.pojo.Student;import  com.mybatis3.pojo.Teacher;import  com.mybatis3.utils.MybatisUtil;import  org.apache.ibatis.session.SqlSession;import  org.junit.Test;import  java.util.List;public  class  Excute  {    @Test      public  void  getstudent () {         SqlSession sqlSession= MybatisUtil.getSqlsession();         StudentMapper mapper=sqlSession.getMapper(StudentMapper.class);         List<Student> getstudentlist = mapper.getstudentlist(1 );         for  (Student student : getstudentlist) {             System.out.println(student);         }         sqlSession.close();     }     @Test      public  void  getteacherlist () {         SqlSession sqlSession= MybatisUtil.getSqlsession();         StudentMapper mapper=sqlSession.getMapper(StudentMapper.class);         List<Teacher> getteacherlist = mapper.getteacherlist();         for  (Teacher teacher : getteacherlist) {             System.out.println(teacher);         }         sqlSession.close();     }     @Test      public  void  selectall () {         SqlSession sqlSession= MybatisUtil.getSqlsession();         StudentMapper mapper=sqlSession.getMapper(StudentMapper.class);         List<Teacher> selectall = mapper.selectall();         for  (Teacher student : selectall) {             System.out.println(student);         }         sqlSession.close();     }     @Test      public  void  selectall2 () {         SqlSession sqlSession= MybatisUtil.getSqlsession();         StudentMapper mapper=sqlSession.getMapper(StudentMapper.class);         List<Teacher> selectall = mapper.selectall2(1 );         for  (Teacher student : selectall) {             System.out.println(student);         }         sqlSession.close();     } } 
 
这里要注意一个小坑,就是我们这样映射查询的时候pojo类中必须要有无参构造方法:https://blog.csdn.net/weixin_50236329/article/details/112312423 
动态SQL环境搭建 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 
 
先把这个SQL搭建了,然后创建一个mybatis子项目搭建一个环境
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package  com.mybatis5.pojo;import  lombok.Data;import  org.apache.ibatis.type.Alias;import  java.util.Date;@Data @Alias("Blog") public  class  Blog  {    private  String id;     private  String title;     private  String author;     private  Date create_time;     private  int  views; } 
 
1 2 3 4 5 6 7 8 package  com.mybatis5.dao;import  com.mybatis5.pojo.Blog;public  interface  BlogMapper  {Boolean AddBlog (Blog blog) ; } 
 
1 2 3 4 5 6 7 8 <?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.mybatis5.dao.BlogMapper" > <insert  id ="AddBlog"  parameterType ="Blog" >     insert into blog(id,title,author,create_time,views) values (#{id},#{title},#{author},#{create_time},#{views}) </insert > </mapper > 
 
1 2 3 4 5 6 7 8 9 10 11 package  com.mybatis5.utils;import  java.util.UUID;public  class  UuidUtils  {    public  static  String getId ()  {         String  uuid  =  UUID.randomUUID().toString().replace("-" , "" );         return  uuid;     } } 
 
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 import  com.mybatis5.dao.BlogMapper;import  com.mybatis5.pojo.Blog;import  com.mybatis5.utils.MybatisUtil;import  com.mybatis5.utils.UuidUtils;import  org.apache.ibatis.session.SqlSession;import  org.junit.Test;import  java.util.Date;public  class  Excute  {    @Test      public  void  addblog () {         Blog blog=new  Blog ();         String uuid= UuidUtils.getId();         Date time=new  Date ();         blog.setId(uuid);         blog.setCreate_time(time);         blog.setAuthor("Nano" );         blog.setTitle("不知道是什么" );         blog.setViews(100 );         SqlSession sqlSession= MybatisUtil.getSqlsession();         BlogMapper  mapper  =  sqlSession.getMapper(BlogMapper.class);         Boolean  aBoolean  =  mapper.AddBlog(blog);         if (aBoolean){             System.out.println("add successfully" );         }         sqlSession.close();     } } 
 
这样先添加个几组数据: 在这我们多加了一个util,用于获取uuid的,在正规场合id不可能是1,2,3
动态SQL IF标签以及常用标签 https://mybatis.org/mybatis-3/zh/dynamic-sql.html  我觉得这部分跟着官方文档走就知道了
IF标签 这里的测试类就是上述构造出来的,这里就只放Xml文件中的语句了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?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.mybatis5.dao.BlogMapper" > <insert  id ="AddBlog"  parameterType ="Blog" >     insert into blog(id,title,author,create_time,views) values (#{id},#{title},#{author},#{create_time},#{views}) </insert >         <select  id ="selectall"  resultType ="Blog"  parameterType ="Map" >              select * from blog where             <if  test ="author != null" >                  author=#{author}             </if >              <if  test ="title != null" >                  and title=#{title}             </if >          </select >  </mapper > 
 
1 2 3 4 5 6 7 8 9 10 11 12 public  void  selectall () {        SqlSession sqlSession= MybatisUtil.getSqlsession();         BlogMapper  mapper  =  sqlSession.getMapper(BlogMapper.class);         Map<String,String> map=new  HashMap <>();         map.put("title" ,"不吉波普不笑" );         map.put("author" ,"Boogipop" );         List<Blog> selectall = mapper.selectall(map);         for  (Blog blog : selectall) {             System.out.println(blog);         }         sqlSession.close();     } 
 
if如同字面意思假如author或者title形参不为空就拼接(这里的author和title是对应#{}的) 但是这样就有个问题,假如我author为空title不为空 sql就为select * from blog where and title=?,这里就要引入Where标签
WHERE标签 1 2 3 4 5 6 7 8 9 10 <select  id ="selectall"  resultType ="Blog"  parameterType ="Map" >             select * from blog             <where > <if  test ="author != null" >                  and author=#{author}             </if >                  <if  test ="title != null" >                      and title=#{title}                 </if >              </where >          </select >  
 
1 2 3 4 5 6 7 8 9 10 11 12 13     @Test      public  void  selectall () {         SqlSession sqlSession= MybatisUtil.getSqlsession();         BlogMapper  mapper  =  sqlSession.getMapper(BlogMapper.class);         Map<String,String> map=new  HashMap <>();         map.put("author" ,"Nano" );         List<Blog> selectall = mapper.selectall(map);         for  (Blog blog : selectall) {             System.out.println(blog);         }         sqlSession.close();     } 
 
 使用where标签会自动为你剔除前置的第一个and ,多了不行,后置了也不行
choose、when、otherwise 这三个就是if,else if,else,感觉没什么区别,也是以一个例子说明
1 2 3 4 5 6 7 8 9 10 11 12 13 <select  id ="chooseall"  resultType ="Blog"  parameterType ="Map" >         select * from blog         <where >              <choose >                  <when  test ="author !=null" >                      and author=#{author}                 </when >                  <when  test ="title !=null" >                      and title=#{title}                 </when >              </choose >          </where >      </select >  
 
1 2 3 4 5 6 7 8 9 10 11 12 13   @Test      public  void  chooseall () {         SqlSession sqlSession= MybatisUtil.getSqlsession();         BlogMapper  mapper  =  sqlSession.getMapper(BlogMapper.class);         Map<String,String> map=new  HashMap <>();         List<Blog> selectall = mapper.chooseall(map);         for  (Blog blog : selectall) {             System.out.println(blog);         }         sqlSession.close();     } 
 
 由于when都不满足就默认全选了
1 2 3 4 5 6 7 8 9 10 11 12 13 @Test     public  void  chooseall () {         SqlSession sqlSession= MybatisUtil.getSqlsession();         BlogMapper  mapper  =  sqlSession.getMapper(BlogMapper.class);         Map<String,String> map=new  HashMap <>();         map.put("title" ,"不吉波普不笑" );         map.put("author" ,"Nano" );         List<Blog> selectall = mapper.chooseall(map);         for  (Blog blog : selectall) {             System.out.println(blog);         }         sqlSession.close();     } 
 
 由于author标签在前,所以优先
trim、set where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。 如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:
1 2 3 <trim  prefix ="WHERE"  prefixOverrides ="AND |OR " >   ... </trim > 
 
然后再来看看set,set就是update的时候用的标签,set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <update  id ="updateblog"  parameterType ="Map" >         update blog         <set >              <if  test ="title!=null" >                  title=#{title},             </if >              <if  test ="author!=null" >                  author=#{author},             </if >              <if  test ="views!=null" >                  views=#{views}             </if >              <where >                  <choose >                      <when  test ="id!=null" >                          id=#{id}                     </when >                      <otherwise >                          id="1"                     </otherwise >                  </choose >              </where >          </set >      </update >  
 
究极无敌的一个update标签,哈哈哈
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  @Test      public  void  updateblog () {         SqlSession sqlSession= MybatisUtil.getSqlsession();         BlogMapper  mapper  =  sqlSession.getMapper(BlogMapper.class);         Map<String,Object> map=new  HashMap <>();         map.put("author" ,"Boogipop" );         map.put("views" ,100000 );         map.put("id" ,"53bbe5be5a174532bcdb1f9951eb0664" );         Boolean  updateblog  =  mapper.updateblog(map);         if (updateblog){             System.out.println("update successfully" );         }         sqlSession.close();     } 
 
这个标签就指定的很智能了,如果不指定id就更改不到信息
include标签 动态SQL foreach标签  foreach的用法其实很简单,以一个例子来说,我们要取数据前三条select * from user where id in(1,2,3) 在不用分页的情况下怎么做到呢?
1 List<Blog> foreachselect (Map map) ; 
 
1 2 3 4 5 6 <select  id ="foreachselect"  resultType ="Blog"  parameterType ="Map" >     select * from blog where author in     <foreach  collection ="strings"  index ="index"  item ="str"  open ="("  separator =","  close =")" >          #{str}     </foreach >  </select > 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Test    public  void  foreach () {        SqlSession sqlSession= MybatisUtil.getSqlsession();        BlogMapper  mapper  =  sqlSession.getMapper(BlogMapper.class);        Map<String,Object> map=new  HashMap <>();        List<String> strings = new  ArrayList <>();        strings.add("Kino" );        strings.add("Nano" );        map.put("strings" ,strings);        List<Blog> foreachselect = mapper.foreachselect(map);        for  (Blog blog : foreachselect) {            System.out.println(blog);        }        sqlSession.close();    } 
 
就这么简单
缓存简介 也就是请求相同资源时假如不做缓存会让性能降低,缓存就是把结果储存,再请求的时候不需要反复执行SQL,只需要执行一次即可 一级缓存是默认开启的: 也就是在你一个sqlsession中,如果你反复执行一条同样的语句,语句的结果就会进入sqlsession的缓存,这样就只会执行一次sql语句,当sqlsession关闭时,缓存也没了
二级缓存 MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。 为了使它更加强大而且易于配置,我们对 MyBatis 3 中的缓存实现进行了许多改进。 默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:<cache/> 基本上就是这样。这个简单语句的效果如下:
映射语句文件中的所有 select 语句的结果将会被缓存。 
映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。 
缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。 
缓存不会定时进行刷新(也就是说,没有刷新间隔)。 
缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。 
缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。 
 
提示 缓存只作用于 cache 标签所在的映射文件中的语句。如果你混合使用 Java API 和 XML 映射文件,在共用接口中的语句将不会被默认缓存。你需要使用 @CacheNamespaceRef 注解指定缓存作用域。 这些属性可以通过 cache 元素的属性来修改。比如: 这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。 可用的清除策略有:
LRU – 最近最少使用:移除最长时间不被使用的对象。 
FIFO – 先进先出:按对象进入缓存的顺序来移除它们。 
SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。 
WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。 
 
默认的清除策略是 LRU。 flushInterval(刷新间隔)属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。 size(引用数目)属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。 readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。 提示 二级缓存是事务性的。这意味着,当 SqlSession 完成并提交时,或是完成并回滚,但没有执行 flushCache=true 的 insert/delete/update 语句时,缓存会获得更新
二级缓存是作用在UserMapper.xml上的,我们使用前需要开启一下settings中的缓存选项: 默认是开的,但是为了让别人知道开了再写一遍: 然后在usermapeer.xml中开启缓存即可
小结 完结啦!mybatis挺方便的,suki