MyBatis

一、MyBatis基础

什么是MyBatis

  • MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。
  • MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
  • MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

为什么要学习MyBatis

  • 简化了JDBC复杂的代码
  • 提高了数据库连接的高效性
  • SQL与代码分离,降低了SQL与代码的耦合性,降低维护成本

前戏准备

  • 开发环境
    • JDK 1.8
    • MySQL 5.7
    • Maven 3.6.1
  • 开发工具
    • IDEA
    • SQLyog
    • Maven
  • 依赖支持
    • JDBC
    • MySQL
    • junit
    • mybatis
      ……

1.1、第一个MyBatis程序

1.1、创建数据库表及数据

  • 数据库准备 ```

    创建数据库

    CREATE DATABASE mybatis; USE mybatis;

创建数据库表

CREATE TABLE user( id INT(20) NOT NULL, name VARCHAR(30) NOT NULL, pwd VARCHAR(20) NOT NULL, PRIMARY KEY(id) )ENGINE=INNODB DEFAULT CHARSET=utf8;

插入数据

INSERT INTO user VALUES (1,’张三’,’147852’), (2,’李四’,’365241’), (3,’王五’,’987564’), (4,’老王’,’258463’), (5,’八戒’,’349182’);

  1. <br />查询结果<br />![](https://gitee.com/hg14150/blogiamges/raw/master/img/image-20210411144341043.png#crop=0&crop=0&crop=1&crop=1&id=nke2T&originHeight=258&originWidth=419&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)
  2. <a name="5e3b473c"></a>
  3. #### 1.2、MyBatis实现连接
  4. <a name="0c2d08e0"></a>
  5. ##### 1.2.1、环境依赖
  6. ```xml
  7. <!--导入依赖-->
  8. <dependencies>
  9. <!--导入myatis依赖-->
  10. <dependency>
  11. <groupId>org.mybatis</groupId>
  12. <artifactId>mybatis</artifactId>
  13. <version>3.5.2</version>
  14. </dependency>
  15. <!--导入mysql依赖-->
  16. <dependency>
  17. <groupId>mysql</groupId>
  18. <artifactId>mysql-connector-java</artifactId>
  19. <version>5.1.47</version>
  20. </dependency>
  21. <!--导入junit依赖-->
  22. <dependency>
  23. <groupId>junit</groupId>
  24. <artifactId>junit</artifactId>
  25. <version>4.12</version>
  26. </dependency>
  27. <!--导入日志依赖-->
  28. <dependency>
  29. <groupId>log4j</groupId>
  30. <artifactId>log4j</artifactId>
  31. <version>1.2.17</version>
  32. </dependency>
  33. <!-- 导入lombok包 -->
  34. <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
  35. <dependency>
  36. <groupId>org.projectlombok</groupId>
  37. <artifactId>lombok</artifactId>
  38. <version>1.18.12</version>
  39. <scope>provided</scope>
  40. </dependency>
  41. </dependencies>
  42. <!--配置过滤配置文件,防止因filter null导致运行失败-->
  43. <build>
  44. <resources>
  45. <resource>
  46. <directory>src/main/java</directory>
  47. <includes>
  48. <include>**/*.properties</include>
  49. <include>**/*.xml</include>
  50. </includes>
  51. <filtering>false</filtering>
  52. </resource>
  53. <resource>
  54. <directory>src/main/resources</directory>
  55. <includes>
  56. <include>**/*.properties</include>
  57. <include>**/*.xml</include>
  58. </includes>
  59. <filtering>false</filtering>
  60. </resource>
  61. </resources>
  62. </build>

1.2.2、JDBC连接类(mybatis-config.xml)
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <configuration>
  6. <!--核心配置文件-->
  7. <environments default="development">
  8. <environment id="development">
  9. <transactionManager type="JDBC"/>
  10. <dataSource type="POOLED">
  11. <property name="driver" value="com.mysql.jdbc.Driver"/>
  12. <property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf8&amp;useSSL=false"/>
  13. <property name="username" value="root"/>
  14. <property name="password" value="123456"/>
  15. </dataSource>
  16. </environment>
  17. </environments>
  18. <!--Mapper.xml文件需要在核心配置下注册-->
  19. <mappers>
  20. <mapper class="com.iflytek.Dao.UserMapper"/>
  21. </mappers>
  22. </configuration>

1.2.3、设计工具类—工厂模式(MyBatisUtils.java)
  1. package com.iflytek.utils;
  2. import org.apache.ibatis.io.Resources;
  3. import org.apache.ibatis.session.SqlSession;
  4. import org.apache.ibatis.session.SqlSessionFactory;
  5. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
  6. import java.io.IOException;
  7. import java.io.InputStream;
  8. /**
  9. * 创建工厂qlSessionFactory实体工具类
  10. * 实现获取sqlSession
  11. */
  12. @SuppressWarnings("ALL")
  13. public class MybatisUilts {
  14. private static SqlSessionFactory sqlSessionFactory;
  15. static {
  16. //1.获取qlSessionFactory对象
  17. try {
  18. String resource = "mybatis-config.xml";
  19. InputStream inputStream = Resources.getResourceAsStream(resource);
  20. sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  21. } catch (IOException e) {
  22. e.printStackTrace();
  23. }
  24. }
  25. //创建执行SQL对象
  26. public static SqlSession getsqlSession(){
  27. return sqlSessionFactory.openSession();
  28. }
  29. }

1.2.4、实体类及实体类接口的编写

1、实体类(User.java)
  1. package com.iflytek.pojo;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. import lombok.ToString;
  6. //创建mybatis实体类
  7. @Data
  8. @NoArgsConstructor
  9. @AllArgsConstructor@ToString
  10. public class User {
  11. private int id;
  12. private String name;
  13. private String password;
  14. }

2、实体类接口(UserMapper.java)
  1. package com.iflytek.Dao;
  2. import com.iflytek.pojo.User;
  3. import org.apache.ibatis.annotations.Param;
  4. import java.util.List;
  5. import java.util.Map;
  6. /**
  7. * 创建操作实体类的接口
  8. */
  9. //
  10. public interface UserMapper {
  11. /**
  12. * @return
  13. * 1.以集合的形式查詢
  14. */
  15. List<User> getUserList();
  16. /**
  17. * @param id
  18. * @return
  19. * 2.根据id查询用户
  20. */
  21. User getUserId(@Param("id") int id);
  22. /**
  23. * @param user
  24. * @return
  25. * 3.插入用户(插入全部信息)
  26. */
  27. int insertUser(User user);
  28. /**
  29. * @param user
  30. * @return
  31. * 4.修改用户信息
  32. */
  33. int updateUser(User user);
  34. /**
  35. * @param id
  36. * @return
  37. * 5.删除用户信息
  38. */
  39. int delete(int id);
  40. }

1.2.5、SQL语句(UserMapper.xml)
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <!--接口实现类转为Mapper配置文件-->
  6. <!--namespace= 绑定一个对应的Dao/Mapper-->
  7. <mapper namespace="com.iflytek.Dao.UserMapper">
  8. <!----------------------------------------------------------------------------------------------------->
  9. <!--执行SQL语句-->
  10. <!--id为接口方法 resultType为集合返回全类名-->
  11. <select id="getUserList" resultType="com.iflytek.pojo.User">
  12. select * from user
  13. </select>
  14. <!----------------------------------------------------------------------------------------------------->
  15. <!--根据id查询,parameterType:数据类型 #{__}查询根据-->
  16. <select id="getUserId" resultType="com.iflytek.pojo.User" >
  17. select * from user where id =#{id}
  18. </select>
  19. <!----------------------------------------------------------------------------------------------------->
  20. <!--插入语句-->
  21. <insert id="insertUser" parameterType="com.iflytek.pojo.User">
  22. insert into user values(#{id},#{name},#{password});
  23. </insert>
  24. <!----------------------------------------------------------------------------------------------------->
  25. <!--修改用户信息-->
  26. <update id="updateUser" parameterType="com.iflytek.pojo.User">
  27. update mybatis.user set name=#{name},password=#{password} where id = #{id};
  28. </update>
  29. <!----------------------------------------------------------------------------------------------------->
  30. <!--删除用户信息-->
  31. <delete id="delete" parameterType="com.iflytek.pojo.User">
  32. delete from user where id=#{id};
  33. </delete>
  34. </mapper>

1.2.6、测试
  1. package com.iflytek.Dao;
  2. import com.iflytek.pojo.User;
  3. import com.iflytek.utils.MybatisUilts;
  4. import org.apache.ibatis.session.SqlSession;
  5. import org.junit.Test;
  6. import java.util.List;
  7. /**
  8. * 业务要求:
  9. * 1.查询所有用户信息
  10. * 2.根据id查询用户信息
  11. * 3.插入用户信息
  12. * 4.修改用户相信
  13. * 5.删除用户相信
  14. *
  15. * 注意事项:
  16. * 1.Mybatis查询必须提交事务 对象.commit()
  17. * 2.没执行一次都要重新释放资源
  18. * 3.返回值类型一定要与UserMapper.java和UserMapper.xml保持一致
  19. */
  20. public class UserMapperTest {
  21. //1.获取配置连接对象
  22. SqlSession sqlSession = MybatisUilts.getsqlSession();
  23. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  24. //查询所有用户信息
  25. @Test
  26. public void queryTest(){
  27. //2.获取getMapper方法
  28. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  29. //3.执行SQL
  30. List<User> userList = mapper.getUserList();
  31. //4.处理结果集
  32. for (User user : userList) {
  33. System.out.println(user);
  34. }
  35. //5.关闭SqlSession
  36. sqlSession.close();
  37. }
  38. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  39. //根据id查询用户
  40. @Test
  41. public void getUserId(){
  42. //2.获取Mapp方法
  43. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  44. //3.执行SQL
  45. User userId = mapper.getUserId(4);
  46. //4.处理结果集
  47. System.out.println(userId);
  48. //5.事务提交
  49. sqlSession.commit();
  50. //6.释放资源
  51. sqlSession.close();
  52. }
  53. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  54. //插入用户
  55. @Test
  56. public void insertUser(){
  57. //2.获取Mapper方法
  58. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  59. //3.获取map方法
  60. mapper.insertUser(new User(2, "张三", "101010"));
  61. //4.提交事务
  62. sqlSession.commit();
  63. //6.释放资源
  64. sqlSession.close();
  65. }
  66. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  67. //修改用户信息
  68. @Test
  69. public void updataUser(){
  70. //2.获取Mapper方法
  71. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  72. //3.执行SQL
  73. mapper.updateUser(new User(1, "八戒", "001100"));
  74. //4.提交事务
  75. sqlSession.commit();
  76. //5.释放资源
  77. sqlSession.close();
  78. }
  79. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  80. //删除用户信息
  81. @Test
  82. public void deleteUser(){
  83. //2.获取Mapper
  84. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  85. //3.执行SQL
  86. mapper.delete(2);
  87. //4.提交事务,在业务中必须要提交事务
  88. sqlSession.commit();
  89. //5.释放资源
  90. sqlSession.close();
  91. }
  92. }

1.3、总结

1、 Mapper.xml必须在MyBatis核心配置文件(mybatis-config.xml)中配置

  1. <!--Mapper.xml文件需要在核心配置下注册-->
  2. <mappers>
  3. <mapper class="com.iflytek.Dao.UserMapper"/>
  4. <mapper resouce="com/iflytek/Dao/UserMapper.xml"/>
  5. </mappers>

2、查询过滤问题,必须添加过滤依赖

  1. <!--配置过滤配置文件,防止因filter null导致运行失败-->
  2. <build>
  3. <resources>
  4. <resource>
  5. <directory>src/main/java</directory>
  6. <includes>
  7. <include>**/*.properties</include>
  8. <include>**/*.xml</include>
  9. </includes>
  10. <filtering>false</filtering>
  11. </resource>
  12. <resource>
  13. <directory>src/main/resources</directory>
  14. <includes>
  15. <include>**/*.properties</include>
  16. <include>**/*.xml</include>
  17. </includes>
  18. <filtering>false</filtering>
  19. </resource>
  20. </resources>
  21. </build>

3、SQL语句的.XML类一定要与实体类接口xxxMapper

  1. <!--SQL语句命名空间绑定实体类接口,只有产生交集才能关联数据库查询-->
  2. <mapper namespace="com.iflytek.Dao.UserMapper">

4、隐射返回类型

  1. <!--结果集返回类型,对应只能返回一个结果,默认情况返回的是实体类接口中方法里的范型或实体类-->
  2. resultType=""
  3. <!--id为接口方法 resultType为集合返回全类名-->
  4. <select id="getUserList" resultType="com.iflytek.pojo.User">
  5. select * from user
  6. </select>
  7. <!--Map类型返回结果集,一般不用-->
  8. resultMap=""

MyBatis - 图1

5、在业务操作中,必须要提交事务和释放资源

  1. //4.提交事务,在业务中必须要提交事务
  2. sqlSession.commit();
  3. //5.释放资源
  4. sqlSession.close();

6、在业务中SQL操作只需要填充业务需求

  1. @Test
  2. public void queryTest(){
  3. //1.获取配置连接对象
  4. SqlSession sqlSession = MybatisUilts.getsqlSession();
  5. //2.获取getMapper方法
  6. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  7. //3.执行SQL
  8. -----------------------------------------------------
  9. //4.处理结果集
  10. for (User user : userList) {
  11. System.out.println(user);
  12. }
  13. //5.提交事务,关闭SqlSession
  14. sqlSession.commit();
  15. sqlSession.close();
  16. }

1.2、CRUD实现原理

  • CRUD实现大致原理一致,代码重复高
  • 除了SQL业务层其他的都是固定的,只要实现SQL业务语句
  • 在业务中建议使用Map的形式实现CURD,以下内容一map为例
  • map操作的好处是可以不用知道数据库里有什么,而是直接按字段查询,参数类型统一
  • CRUD每个业务的实现都要提交事务和资源释放

    1. //4.提交事务,在业务中必须要提交事务
    2. sqlSession.commit();
    3. //5.释放资源
    4. sqlSession.close();
    5. //参数类型统一 .xml
    6. parameterType="map"

1、数据库设计
  1. CREATE DATABASE `mybatis`;
  2. USE `mybatis`;
  3. CREATE TABLE `user` (
  4. `id` INT(20) NOT NULL,
  5. `name` VARCHAR(30) NOT NULL,
  6. `pwd` VARCHAR(20) NOT NULL,
  7. `gender` VARCHAR(2) NOT NULL,
  8. `height` INT(5) DEFAULT NULL,
  9. PRIMARY KEY (`id`)
  10. ) ENGINE=INNODB DEFAULT CHARSET=utf8;
  11. INSERT INTO `user` VALUES
  12. (1,'张三','147852','男',180),
  13. (2,'李四','365241','女',179),
  14. (3,'王五','987564','男',169),
  15. (4,'老王','258463','女',150),
  16. (5,'八戒','349182','男',172);

2、实体类接口
  1. package com.iflytek.Dao;
  2. import com.iflytek.pojo.User;
  3. import java.util.List;
  4. import java.util.Map;
  5. /**
  6. * 创建Map方法实现类的接口
  7. */
  8. public interface UserMapper_2 {
  9. //查询全部信息
  10. List<User> getUserlist();
  11. //2.根据id查询对象
  12. User getUserId(Map<String,Object> map);
  13. //3.添加对象信息
  14. void insertUser(Map<String,Object> map);
  15. //4.修改对象
  16. int update(Map<String,Object> map);
  17. //5.删除对象
  18. int delete(Map<String,Object> map);
  19. //6.模糊查询
  20. List<User> getUserlike(String value);
  21. }

3、SQL语句
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <!--接口实现类转为Mapper配置文件-->
  6. <!--namespace= 绑定一个对应的Dao/Mapper-->
  7. <mapper namespace="com.iflytek.Dao.UserMapper_2">
  8. <!--执行SQL语句-->
  9. <!--id为接口方法 resultType为集合返回全类名-->
  10. <!--查询所有对象-->
  11. <select id="getUserlist" resultType="com.iflytek.pojo.User">
  12. select * from user_2
  13. </select>
  14. <!--根据id查询对象-->
  15. <select id="getUserId" parameterType="map" resultType="com.iflytek.pojo.User">
  16. select * from user_2 where id=#{userid};
  17. </select>
  18. <!--添加对象-->
  19. <insert id="insertUser" parameterType="map">
  20. insert into user_2 values(#{id},#{name},#{password},#{gender},#{height});
  21. </insert>
  22. <!--修改对象-->
  23. <update id="update" parameterType="map">
  24. update user_2 set name=#{name},password=#{password},gender=#{gender},height=#{height} where id=#{id};
  25. </update>
  26. <!--删除对象-->
  27. <delete id="delete" parameterType="map">
  28. delete from user_2 where id=#{id};
  29. </delete>
  30. <!--模糊查询-->
  31. <select id="getUserlike" resultType="com.iflytek.pojo.User">
  32. <!-- "%"#{value}"%"防止SQL注入-->
  33. select * from user_2 where name like "%"#{value}"%";
  34. </select>
  35. </mapper>

4、业务实现
  1. package com.iflytek.Dao;
  2. import com.iflytek.pojo.User;
  3. import com.iflytek.utils.MybatisUtils_2;
  4. import org.apache.ibatis.session.SqlSession;
  5. import org.junit.Test;
  6. import java.util.HashMap;
  7. import java.util.List;
  8. import java.util.Map;
  9. public class UserMapperTest_2 {
  10. //1.获取配置连接对象
  11. SqlSession sqlSession=MybatisUtils_2.getsqlSession();
  12. //2.获取getMapper方法
  13. UserMapper_2 mapper = sqlSession.getMapper(UserMapper_2.class);
  14. //查询所有对象
  15. @Test
  16. public void getUserlist(){
  17. //3.执行sql
  18. List<User> userlist = mapper.getUserlist();
  19. //4.处理结果集
  20. for (User user : userlist) {
  21. System.out.println(user);
  22. }
  23. //5.提交事务
  24. sqlSession.commit();
  25. //6.释放资源
  26. sqlSession.close();
  27. }
  28. //根据id查询对象
  29. @Test
  30. public void getUserId(){
  31. //3.执行sql
  32. Map<String, Object> map = new HashMap<String, Object>();
  33. //获取查询map地址
  34. map.put("userid",1);
  35. //提交amp地址
  36. User userId = mapper.getUserId(map);
  37. //处理结果集
  38. System.out.println(userId);
  39. //4.提交事务
  40. sqlSession.commit();
  41. //5.释放资源
  42. sqlSession.close();
  43. }
  44. //添加对象
  45. @Test
  46. public void insertUser(){
  47. //3.执行SQL
  48. HashMap<String, Object> map = new HashMap<String, Object>();
  49. //写入添加信息
  50. map.put("id",7);
  51. map.put("name","阿珂");
  52. map.put("password","112233");
  53. map.put("gender","女");
  54. map.put("height",160);
  55. //提交写入信息
  56. mapper.insertUser(map);
  57. //4.提交事务
  58. sqlSession.commit();
  59. //释放资源
  60. sqlSession.close();
  61. }
  62. //修改对象信息
  63. @Test
  64. public void update(){
  65. //3.执行SQL,获取HashMap
  66. Map<String, Object> map = new HashMap<String, Object>();
  67. //写入修改信息
  68. map.put("id",1);
  69. map.put("name","一婵");
  70. map.put("password","101010");
  71. map.put("gender","女");
  72. map.put("height",179);
  73. //提交修改信息
  74. mapper.update(map);
  75. //4.提交事务
  76. sqlSession.commit();
  77. //5.释放资源
  78. sqlSession.close();
  79. }
  80. //删除对象
  81. @Test
  82. public void delete(){
  83. //3.执行SQL,获取HashMap
  84. Map<String, Object> map = new HashMap<String, Object>();
  85. //写入删除id信息
  86. map.put("id",6);
  87. //提交信息
  88. mapper.delete(map);
  89. //4.提交事务
  90. sqlSession.commit();
  91. //释放资源
  92. sqlSession.close();
  93. }
  94. //模糊查询
  95. @Test
  96. public void getUserlike(){
  97. UserMapper_2 mapper = sqlSession.getMapper(UserMapper_2.class);
  98. List<User> userlike = mapper.getUserlike("%李%");
  99. for (User user : userlike) {
  100. System.out.println(user);
  101. }
  102. sqlSession.commit();
  103. sqlSession.close();
  104. }
  105. }

5、总结
  • 业务实现的固定搭配 ```java //查询所有对象 @Test public void getUserlist(){

    1. //1.获取配置连接对象
    2. SqlSession sqlSession=MybatisUtils_2.getsqlSession();
    3. //2.获取getMapper方法
    4. UserMapper_2 mapper = sqlSession.getMapper(UserMapper_2.class);
    5. //3.执行sql
    6. Map<String, Object> map = new HashMap<String, Object>();
    7. //处理SQL业务
  1. //4.处理结果集
  2. for (User user : userlist) {
  3. System.out.println(user);
  4. }
  5. //5.提交事务
  6. sqlSession.commit();
  7. //6.释放资源
  8. sqlSession.close();
  9. }
  1. - 多参数情况使用**parameterType="map"**
  2. <a name="e4a20289"></a>
  3. ### 1.3、配置优化
  4. - MyBatis-config.xml中需要配置的内容有几下几个点,在配置文件中一定要按照这个顺序配置
  5. ![](https://gitee.com/hg14150/blogiamges/raw/master/img/image-20210412110503579.png#crop=0&crop=0&crop=1&crop=1&id=twFhF&originHeight=377&originWidth=862&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)
  6. <a name="48f04ffe"></a>
  7. ##### 1.3.1、properties
  8. - `db.properties`
  9. ```properties
  10. driver=com.mysql.jdbc.Driver
  11. url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8
  12. username=root
  13. password=123456
  • 动态引用配置
  1. <properties resource="db.properties">
  2. <property name="username" value="root"/>
  3. <property name="password" value="123456"/>
  4. </properties>
  • 可以通过properties动态引用配置文件属性,主要引用db.properties
  1. <dataSource type="POOLED">
  2. <property name="driver" value="${driver}"/>
  3. <property name="url" value="${url}"/>
  4. <property name="username" value="${username}"/>
  5. <property name="password" value="${password}"/>
  6. </dataSource>
  • 在使用外部引用时,优先级外部引用大于内部引用
  • 整体效果 ```xml <?xml version=”1.0” encoding=”UTF-8” ?> <!DOCTYPE configuration
    1. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    2. "http://mybatis.org/dtd/mybatis-3-config.dtd">

  1. <settings>
  2. <setting name="logImpl" value="STDOUT_LOGGING"/>
  3. </settings>
  4. <!--设置别名,减少冗余-->
  5. <typeAliases>
  6. <!--第一种方法,获取全类名并取别名-->
  7. <typeAlias type="com.iflytek.pojo.User" alias="User"/>
  8. <!--第一种方法,扫描所需类名的上级全类名-->
  9. <package name="com.iflytek.pojo"/>
  10. <!--实体类较少时用第一种,实体类较多时用第二种-->
  11. </typeAliases>
  12. <!--核心配置文件-->
  13. <!--envrionments可配置多环境-->
  14. <environments default="development">
  15. <!--环境配置一 -->
  16. <environment id="development">
  17. <!--数据库管理器:1.JDBC 2.MANAGED-->
  18. <transactionManager type="JDBC"/>
  19. <!--连接池的实现-->
  20. <dataSource type="POOLED">
  21. <property name="driver" value="${driver}"/>
  22. <property name="url" value="${url}"/>
  23. <property name="username" value="${username}"/>
  24. <property name="password" value="${password}"/>
  25. </dataSource>
  26. </environment>
  27. </environments>
  28. <!--Mapper.xml文件需要在核心配置下注册-->
  29. <mappers>
  30. <mapper resource="com/iflytek/Dao/UserMapper_3.xml"/>
  31. <!--通过class和package方法必须保证接口与配置文件同名且在同一个包下面-->
  32. <!--<mapper class="com.iflytek.Dao.UserMapper_2"/>-->
  33. <!--<package name="com.iflytek.Dao.UserMapper_2"/>-->
  34. </mappers>

  1. <a name="b8c14e5d"></a>
  2. ##### 1.3.2、Settings
  3. ```xml
  4. <!--常用设置-->
  5. <settings>
  6. <!--默认开启配置缓存-->
  7. <setting name="cacheEnabled" value="true"/>
  8. <!--默认开启懒加载,延迟加载,一般选择关闭-->
  9. <setting name="lazyLoadingEnabled" value="false"/>
  10. <!--允许返回多个结果集-->
  11. <setting name="multipleResultSetsEnabled" value="true"/>
  12. <!--默认开启实体类驼峰命名-->
  13. <setting name="mapUnderscoreToCamelCase" value="false"/>
  14. <!--设置日志实现-->
  15. <setting name="logImpl" value="STDOUT_LOGGING"/>
  16. </settings>

1.3.3、typeAliases
  • 类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写
    • 按类名起别名 ```xml
- 按包名起别名xml - 在包下的类中添加注解,默认情况下别名使用小写java @Alias(“User”) public class User { … } - 第一种方式,可以DIY别名,且适用与实体类少的情况 - 第二种方式,别名即类名,适用与实体类多的情况 <a name="e81e7d66"></a> ##### 1.3.4、environments - 默认环境,默认开发模式**default=“development”**,可改选项xml - 默认使用的环境 ID(比如:default="development") - 每个 environment 元素定义的环境 ID(比如:id="development") - 事务管理器的配置(比如:type="JDBC"),还有MANAGED - 数据源的配置(比如:type="POOLED")默认pooled是因为它能让web快速响应请求 <a name="009a21c6"></a> ##### 1.3.5、mappers 建议使用相对路径和限定全类名 - 使用限定全类名绑定时要注意,实体类接口和SQL业务查询文件必须在同一个包下,且类名一致xml <a name="64fbf7d4"></a> ### 1.4、生命周期及作用域 生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。 **SqlSessionFactoryBuilder —> SqlSessionFactory —> SqlSession** - <a name="SqlSessionFactoryBuilder"></a> #### SqlSessionFactoryBuilder - 这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了 - <a name="SqlSessionFactory"></a> #### SqlSessionFactory - 一旦被创建就应该在应用的运行期间一直存在,不允许丢弃它或重新创建另一个实例, - <a name="SqlSession"></a> #### SqlSession - 每个线程都应该有它自己的 SqlSession 实,相当于多态实例化的请求,用完需要关闭<br />![](https://gitee.com/hg14150/blogiamges/raw/master/img/image-20210412122452842.png#crop=0&crop=0&crop=1&crop=1&id=FVNGR&originHeight=500&originWidth=873&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=) <a name="99c5f8d5"></a> ### 1.5、ResultMap - 结果集映射解决了数据库字段名与实体类变量名不一致的问题,也仅限适用于字段名与变量名不同的情况xml - column是数据库字段名,property是实体类变量名,通过属性指向映射将两者连接 - 查询时候直接引用参数,resultMap=“ ”引用xml - reslutMap的优秀在于,映射不相同的字段名跟变量名,一致的不用映射 <a name="b889bc53"></a> ## 二、MyBatis进阶 <a name="9fa7b21d"></a> ### 2.1、日志解析 - Mybatis内置的日志工厂提供日志功能,具体的日志实现有以下几种工具: - SLF4J - **Apache Commons Logging**(默认使用) - Log4j 2 - Log4j - JDK logging - 标准日志实现xml - 有需求就会有市场,在开发中log4j才是日志王者 - Log4j是Apache的一个开源项目 - 通过使用Log4j,我们可以控制日志信息输送的目的地:控制台,文本,GUI组件.... - 我们也可以控制每一条日志的输出格式; - 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。 - 使用步骤: 1. 导入依赖(**pom.xml**)xml log4j log4j 1.2.17 2. 编写配置文件(**log4j.properties**)properties #将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码 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/iflytek.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设置日志实现xml 4. 测试日志生成java //注意导包:org.apache.log4j.Logger static Logger logger = Logger.getLogger(MyTest.class); @Test public void getUserlist(){ /** 日志级别: 等级info,消息在粗粒度级别上突出强调应用程序的运行过程 等级为debug,低于debug就不会输出 等级error,发生错误事件,但仍然不影响系统的继续运行 / logger.info(“info:进入selectUser方法”); logger.debug(“debug:进入selectUser方法”); logger.error(“error: 进入selectUser方法”); //3.执行sql List userlist = mapper.getUserlist(); //4.处理结果集 for (User user : userlist) { System.out.println(user); } //5.提交事务 sqlSession.commit(); //6.释放资源 sqlSession.close(); } <a name="6d693c0d"></a> ### 2.2、分页实现 分页在商场类项目中,使用最为广泛,使用分页有以下好处 - 提高了用户体验 - 降低了数据刷新的频率,减少宕机的风险 <a name="4fc3e724"></a> ##### 1、基于持久层的分页实现 - **Limit实现分页** - SQL语法 #语法 SELECT FROM table LIMIT stratIndex,pageSize SELECT FROM table LIMIT 5,10; // 检索记录行 6-15
#为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1:
SELECT FROM table LIMIT 95,-1; // 检索记录行 96-last.
#如果只给定一个参数,它表示返回最大的记录行数目:
SELECT
FROM table LIMIT 5; //检索前 5 个记录行
#换句话说,LIMIT n 等价于 LIMIT 0,n。 - 使用步骤 1. 修改Mapper.xml文件xml 2. Mapper.java接口,参数为mapxml //选择全部用户实现分页 List selectUser(Map map); ``` 3. 测试
推断:起始位置 = (当前页面 - 1 ) 页面大小 java //分页查询 , 两个参数startIndex , pageSize @Test public void testSelectUser() { SqlSession session = MybatisUtils.getSession(); UserMapper mapper = session.getMapper(UserMapper.class); int currentPage = 1; //第几页 int pageSize = 2; //每页显示几个 Map<String,Integer> map = new HashMap<String,Integer>(); map.put("startIndex",(currentPage-1)*pageSize); map.put("pageSize",pageSize); List<User> users = mapper.selectUser(map); for (User user: users){ System.out.println(user); } session.close(); } - RowBounds实现分页 - 使用步骤 1. mapper接口 java //选择全部用户RowBounds实现分页 List<User> getUserByRowBounds(); 2. mapper.xml文件 xml <select id="getUserByRowBounds" resultMap="UserMap"> select * from user </select> 3. 测试 java //rowbunds实现分页查询 @Test public void getUserByRowBunds(){ UserMapper_4 mapper = sqlSession.getMapper(UserMapper_4.class); int currentPage = 2; //第几页 int pageSize = 2; //每页显示几个 RowBounds rowBounds = new RowBounds((currentPage-1)*pageSize,pageSize); //通过session.**方法进行传递rowBounds,[此种方式现在已经不推荐使用了] List<User> users = sqlSession.selectList("com.iflytek.Dao.UserMapper_4.getUserByRowBounds", null, rowBounds); for (User user: users){ System.out.println(user); } sqlSession.commit(); sqlSession.close(); } ##### 2、总结 - limit分页方式是数据库层实现的分页方式 - rowbunds分页方式是Java层面实现的分页方式 ### 2.3、神奇的注解 - 使用步骤 1. 编写实体类接口方法 1. 在方法体上添加SQL注解,以达到Mapper.xml的效果 java package com.iflytek.Dao; import com.iflytek.pojo.User; import org.apache.ibatis.annotations.*; import java.util.List; import java.util.Map; //注解查询 @SuppressWarnings("ALL") public interface UserMapper_5 { //注解查询全部对象 @Select("select * from user") List<User> getUsers(); //注解根据id查询对象 @Select("select * from user where id=#{id}") User getUserById(@Param("id") int id); //注解添加对象 @Insert(" insert into user values(#{id},#{name},#{password},#{gender},#{height})") int insertUser(Map<String,Object> map); //注解修改对象 @Update("update user set name=#{name},password=#{password},gender=#{gender},height=#{height} where id=#{id}") int update(Map<String, Object> map); //注解删除对象 @Delete(" delete from user where id=#{id}") int delete(Map<String, Object> map); } 3. 测试 java //注解添加对象 @Test public void insertUser(){ //1.获取配置连接对象 SqlSession sqlSession= MybatisUtils_5.getsqlSession(); //2.获取getMapper方法 UserMapper_5 mapper = sqlSession.getMapper(UserMapper_5.class); //注意导包:org.apache.log4j.Logger static Logger logger = Logger.getLogger(String.valueOf(UserMapper_5.class)); HashMap<String, Object> map = new HashMap<String, Object>(); //写入添加信息 map.put("id",7); map.put("name","张飞"); map.put("password","102938"); map.put("gender","男"); map.put("height",190); //提交写入信息 mapper.insertUser(map); //4.提交事务 sqlSession.commit(); //释放资源 sqlSession.close(); } - 总结 - 使用注解可以简化代码,这个过程主要体现在Mapper.xml文件的省略 - 注解开发只适用于简单常见的业务,过于复杂的业务不建议使用 - 因为使用注解,不需要创建Mapper.xml文件,在配置文件中绑定注册只能以限定全类名或包名的形式 xml <!--绑定接口,每写一个就必须先绑定注册,使用*通配符匹配绑定能到达最大化简略--> <mappers> <mapper class="com.iflytek.Dao.UserMapper_5"/> </mappers> - 在注解开发中,可以设置事务的自动提交,方便测试 java //实体类接口,设置为true public static SqlSession getsqlSession(){ return sqlSessionFactory.openSession(true); } - 关于@Param()注解 - 基本类型或String的参数,都需要加上 - 引用类型不需要加上 - 可以同时添加不同的参数注解 ### 2.4、复杂查询环境 #### 1、MyBatis执行流程 - MyBatis程序执行路线 MyBatis - 图2 - 执行流程 MyBatis - 图3 #### 2、多查询处理 - 多数据查询无非就是一对多和多对一,以及关联多表查询 - 以老师和学生为例创建主键外键关联表,但实际开发不建议是由物理外键 #创建教师表 create table `teacher`( `id` int(10) not null, `name` varchar(30) default null, primary key (`id`) )engine=innoDB default charset =utf8; #插入数据 insert into `teacher`(`id`,`name`) values(1,'张三'); #创建学生表 create table `student`( `id` int(10) not null , `name` varchar(30) default null , `tid` int(10) default null, primary key (`id`), key `fktid`(`tid`), constraint `fktid` foreign key (`tid`) references `teacher`(`id`) )engine =innoDB default charset =utf8; #插入数据 insert into `student` values (1,'小红',1); insert into `student` values (1,'小黄',1); insert into `student` values (2,'小黄',1); insert into `student` values (3,'小兰',1); insert into `student` values (4,'小白',1); insert into `student` values (5,'小青',1); insert into `student` values (6,'小五',1); - 物理外键的关联效果
MyBatis - 图4 ##### 1、一对多 - 结果集嵌套跟结果集映射是一个重要的思想 - 一对多的查询通常使用结果集嵌套来实现 xml <!--查询所有对象--> <select id="getTeacher_1" resultType="com.iflytek.pojo.Teacher"> select * from teacher t,student s where s.id = t.id </select> - 整合集合类型使用collection标签,java映射类型为 javaType=”ArrayList” ofType=”Student” - javaType & ofType - javaType 用来指定实体类中的属性 - ofType 用来指定映射到List或集合中的实体类 ##### 2、多对一 - 提出需求——查询所有学生信息以及对应老师的信息 - 需求分析 - 查询学生表所有信息 select * from `student`; - 查询对应老师的信息 select * from `teacher`; - 关联查询学生信息对应老师信息的自查询 select * from `student` as s,`teacher` as t where s.id=t.id; - 业务实现 xml <!--查询学生信息--> <select id="getStudent" resultMap="Student_Teacher"> select * from student </select> - 在java中,每个表对应不同的实体类,这导致了Mapper.xml文件不同,使用SQL语句达不到关联查询的效果 - 因此需要使用association标签整合,整合对象为teacher表,整合列为tid.java映射类型为 resultType=”Teacher”,select查询的对象为id=”getTeacher”,相当于整合谁类型就归谁 - 结果集嵌套处理 #关联Teacher表查询所有学生记录,联表查询 <select id="getStudentLinkTeacher" resultMap="Student_Teacher_2"> select s.id sid,s.name sname,t.name tname from student s,teacher t where s.tid = t.id; </select> - 从SQL层的联表查询,相对来说难度稍大,但是效率极高,安全性相当 - 最好使用结果嵌做业务查询 #### 3、动态SQL问题 什么是动态SQL:动态SQL指的是根据不同的查询条件 , 生成不同的Sql语句,注解开发难以做到这一点。 > MyBatis 的强大特性之一便是它的动态 SQL。 >
> 如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。 >
> 例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。 >
> 利用动态 SQL 这一特性可以彻底摆脱这种痛苦。 >
> 虽然在以前使用动态 SQL 并非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 映射语句中的强大的动态 SQL 语言得以改进这种情形。 >
> 动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。 > - if > - choose (when, otherwise) > - trim (where, set) > - foreach > —- —- - 创建数据库 #创建数据库表 create table `blog`( `id` varchar(50) not null comment '博客id', `title` varchar(30) default null comment '博客标题', `author` varchar(50) default null comment '作者', `createTtime` datetime comment '创建时间', `views` int(100) not null comment '浏览量', primary key (`id`) )engine =innoDB default charset =utf8; #插入数据 insert into `blog` values ('1','java基础','张三','2020-10-10',100); insert into `blog` values ('2','mysql基础','李四','2020-10-11',110); insert into `blog` values ('3','redis基础','王五','2021-04-10',120); insert into `blog` values ('4','python基础','八戒','2019-10-10',101); - 创建工程 - 编写工具类(MyBatisUtils_9) java package com.iflytek.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; /** * 创建sqlSessionFactory工厂实体类工具 * 获取sqlsession对象 * * 在java中,jvm先加载的是静态代码块 */ public class MybatisUtils_9 { //1.创建sqlSessionFactory工厂实体类 private static SqlSessionFactory sqlSessionFactory; //创建代码块 static{ //获取sqlsession对象 try { //连接配置文件 String resource = "mybatis-config-9.xml"; //获取扫描 InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } //实体类接口 public static SqlSession getsqlSession(){ return sqlSessionFactory.openSession(); } } - 编写UUID工具类(IDUtils.java) java package com.iflytek.utils; import org.junit.Test; import java.util.UUID; @SuppressWarnings("all") public class IDutils { //设置随机生成id public static String getId(){ //取消- return UUID.randomUUID().toString().replaceAll("-",""); } @Test public void t(){ System.out.println(IDutils.getId()); System.out.println(IDutils.getId()); System.out.println(IDutils.getId()); } } - 编写mybatis配置文件(mybatis-config-9.xml) ```xml <?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">
  1. <!--核心配置文件-->
  2. <!--envrionments可配置多环境-->
  3. <environments default="development">
  4. <!--环境配置一 -->
  5. <environment id="development">
  6. <!--数据库管理器:1.JDBC 2.MANAGED-->
  7. <transactionManager type="JDBC"/>
  8. <!--连接池的实现-->
  9. <dataSource type="POOLED">
  10. <property name="driver" value="${driver}"/>
  11. <property name="url" value="${url}"/>
  12. <property name="username" value="${username}"/>
  13. <property name="password" value="${password}"/>
  14. </dataSource>
  15. </environment>
  16. </environments>
  1. <mappers>
  2. <!--使用通配符注册绑定配置文件-->
  3. <mapper resource="BlogMapper.xml"/>
  4. </mappers>

  1. - 编写数据库连接池配置文件(db.properties
  2. ```properties
  3. driver=com.mysql.jdbc.Driver
  4. url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8
  5. username=root
  6. password=123456
  • 编写实体类(Blog.java) ```java package com.iflytek.pojo;

import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString;

import java.util.Date; @Data @NoArgsConstructor @AllArgsConstructor @ToString @SuppressWarnings(“all”) public class Blog { private String id; private String title; private String author; private Date createTtime; //属性名与字段名不一致哦 private int views; }

  1. - 编写实体类接口(BlogManpper.java
  2. ```java
  3. package com.iflytek.Dao;
  4. import com.iflytek.pojo.Blog;
  5. import org.apache.ibatis.annotations.Select;
  6. import java.util.List;
  7. import java.util.Map;
  8. @SuppressWarnings("all")
  9. public interface BlogMapper {
  10. //1.插入记录
  11. int insertBlog(Blog blog);
  12. }
  1. <!--插入记录-->
  2. <insert id="insertBlog" parameterType="blog">
  3. insert into blog values(#{id},#{title},#{author},#{createTtime},#{views});
  4. </insert>

  1. - 测试
  2. ```java
  3. package com.iflytek.Dao;
  4. import com.iflytek.pojo.Blog;
  5. import com.iflytek.utils.IDutils;
  6. import com.iflytek.utils.MybatisUtils_9;
  7. import org.apache.ibatis.session.SqlSession;
  8. import org.junit.Test;
  9. import java.util.Date;


import java.util.HashMap;
import java.util.List;
@SuppressWarnings(“all”)
public class BlogMapperTest {

  1. //1.获取连接对象
  2. SqlSession sqlSession = MybatisUtils_9.getsqlSession();
  3. //2.获取mapper声明
  4. BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
  5. //添加记录
  6. @Test
  7. public void getBlogTest(){
  8. //创建执行对象
  9. Blog blog = new Blog();
  10. //添加记录
  11. blog.setId(IDutils.getId());
  12. blog.setTitle("Mybatis");
  13. blog.setAuthor("狂神说");
  14. blog.setCreateTtime(new Date());
  15. blog.setViews(9999);
  16. mapper.insertBlog(blog);
  17. blog.setId(IDutils.getId());
  18. blog.setTitle("Java");
  19. mapper.insertBlog(blog);
  20. blog.setId(IDutils.getId());
  21. blog.setTitle("Spring");
  22. mapper.insertBlog(blog);
  23. blog.setId(IDutils.getId());
  24. blog.setTitle("微服务");
  25. mapper.insertBlog(blog);
  26. sqlSession.commit();
  27. sqlSession.close();
  28. }

}

  • 在没有学习MyBatis-Plus之前,动态SQL是后台与数据库交互最简单的实现方式,没有之一。

1、动态SQL-IF

MyBatis - 图5

动态IF查询只要用于,多条件查询时灵活切换条件

  • 实体类接口
    1. //2.if条件查询之博客查询
    2. List<Blog> queryBlogIF(Map map);
  • SQL语句(该方法也称为sql引用)

    1. <!--if条件查询-->
    2. <select id="queryBlogIF" parameterType="map" resultType="blog">
    3. select * from blog
    4. <!--where自动匹配条查询条件是否满足-->
    5. <where>
    6. <include refid="if-title-author"/>
    7. </where>
    8. </select>
    9. <!--sql片段插入公共部分,where语法不能使用,实现代码多次复用,提高程序效率-->
    10. <sql id="if-title-author">
    11. <if test="title !=null">
    12. title =#{title}
    13. </if>
    14. <if test="author !=null">
    15. and author =#{author}
    16. </if>
    17. </sql>
  • 测试

    1. //实现动态if条件查询一
    2. @Test
    3. public void quaryBlogTest(){
    4. //1.获取连接对象
    5. SqlSession sqlSession = MybatisUtils_9.getsqlSession();
    6. //2.获取mapper声明
    7. BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    8. //实现动态查询语句的关键
    9. HashMap map = new HashMap();
    10. //实现动态SQL
    11. map.put("title","微服务");
    12. map.put("author","狂神说");
    13. List<Blog> blogs = mapper.queryBlogIF(map);
    14. for (Blog blog : blogs) {
    15. System.out.println(blog);
    16. }
    17. //提交事务
    18. sqlSession.commit();
    19. //释放资源
    20. sqlSession.close();
    21. }
  • SQL语句动态拼接,查询什么字段,自动拼接什么字段

2、动态SQL-常用语句

MyBatis - 图6

  • 实体类接口
    1. //2.if条件查询之博客查询
    2. List<Blog> queryBlogIF(Map map);
  • SQL语句(Mapper.xml)
    1. <!--choose条件查询-->
    2. <select id="queryBlogChoose" parameterType="map" resultType="blog">
    3. select *from blog
    4. <where>
    5. <!--choose只要满足所有条件中的靠前的一个就停止查询-->
    6. <choose>
    7. <!--满足条件查询一下内容-->
    8. <when test="title !=null">
    9. title=#{title}
    10. </when>
    11. <when test="author !=null">
    12. and author=#{author}
    13. </when>
    14. <!--不满足条件查询下面内容-->
    15. <otherwise>
    16. and views = #{views}
    17. </otherwise>
    18. </choose>
    19. </where>
    20. </select>
  • 测试

    1. //实现动态choose条件查询一
    2. @Test
    3. public void quaryBlogTest_2() {
    4. //1.获取连接对象
    5. SqlSession sqlSession = MybatisUtils_9.getsqlSession();
    6. //2.获取mapper声明
    7. BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    8. //实现动态查询语句的关键
    9. HashMap map = new HashMap();
    10. // map.put("views",9999);
    11. map.put("title","Java");
    12. List<Blog> blogs = mapper.queryBlogChoose(map);
    13. for (Blog blog : blogs) {
    14. System.out.println(blog);
    15. }
    16. //提交事务
    17. sqlSession.commit();
    18. //释放资源
    19. sqlSession.close();
    20. }
  • SQL拼接在多条件查询下只识别第一个条件,不论顺序先后

3、动态SQL-Foreach
  • 实体类接口
    1. //查询前三条记录
    2. List<Blog> queryBlogForeach(Map map);
  • SQL语句(Mapper.xml)
    1. <select id="queryBlogForeach" parameterType="map" resultType="blog">
    2. select * from mybatis.blog
    3. <where>
    4. <foreach collection="ids" item="id" open="and (" close=")" separator="or">
    5. id = #{id}
    6. </foreach>
    7. </where>
    8. </select>
  • 测试
    1. //实现动态foreach查询
    2. @Test
    3. public void queryBlogForeach(){
    4. //实现动态查询语句的关键
    5. HashMap map = new HashMap();
    6. //执行动态SQL
    7. ArrayList<Integer> ids = new ArrayList<Integer>();
    8. ids.add(1);
    9. ids.add(2);
    10. ids.add(3);
    11. map.put("ids",ids);
    12. List<Blog> blogs = mapper.queryBlogForeach(map);
    13. for (Blog blog : blogs) {
    14. System.out.println(blog);
    15. }
    16. //提交事务
    17. sqlSession.commit();
    18. //释放资源
    19. sqlSession.close();
    20. }

2.5、MyBatis缓存原理

何为缓存?

  • 什么是缓存 [ Cache ]?
    • 存在内存中的临时数据。
    • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。
  • 为什么使用缓存?
    • 减少和数据库的交互次数,减少系统开销,提高系统效率。
  • 什么样的数据能使用缓存?
    • 经常查询并且不经常改变的数据。
    • 缓存读数据,不缓存写数据。

缓存的多样性

Mamecache
  • 一中分布式的高速缓存系统
    • 以更小的资源支持更大负载网站的运行,以小博大
    • 尽量减少用户等待时间,节省系统资源开销,节省带宽使用
    • Memcache内存缓存技术、静态化技术、mysql优化
  • Mamecache与Redis的区别与联系
    • redis:支持比较多的数据类型(String、list、set、sortset/hash),redis支持集合计算的(set类型支持),每个key最大数据存储量为1G,redis是新兴的内存缓存技术,对各方面支持不完善,支持持久化操作
    • memcache:老牌的内存缓存技术,对相关领域支持比较丰富,window和linux都可以使用,各种框架(tp、yii等等)都支持使用,session的信息可以非常方便的保存到该memcache中,每个key保存的数据量最大为1M,支持的数据类型比较单一,就是String类型,不支持持久化

EhCache
  • 一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认CacheProvider
    • 一种广泛使用的开源Java分布式缓存
    • 主要面向通用缓存,Java EE和轻量级容器
    • 它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet过滤器,支持REST和SOAP api等特点
    • 快速、简单、支持多种缓存策略
    • 缓存数据有两级:内存和磁盘,因此无需担心容量问题
    • 缓存数据会在虚拟机重启的过程中写入磁盘
    • 可以通过RMI、可插入API等方式进行分布式缓存
    • 具有缓存和缓存管理器的侦听接口
    • 支持多缓存管理器实例,以及一个实例的多个缓存区域
    • 提供Hibernate的缓存实现
  • EhCahcee与Redis的区别与联系
    • Redis是通过socket访问到缓存服务,效率比Ehcache低,比数据库要快很多,处理集群和分布式缓存方便,有成熟的方案。
      • 如果是单个应用或者对缓存访问要求很高的应用,用ehcache。如果是大型系统,存在缓存共享、分布式部署、缓存内容很大的,建议用redis。
    • EhCache直接在jvm虚拟机中缓存,速度快,效率高;但是缓存共享麻烦,集群分布式应用不方便。
      • ehcache也有缓存共享方案,不过是通过RMI或者Jgroup多播方式进行广播缓存通知更新,缓存共享复杂,维护不方便;简单的共享可以,但是涉及到缓存恢复,大数据缓存,则不合适。

Redis
  • 一个优秀的用于缓存的NoSQL

MyBatis缓存
  • MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存,缓存可以极大的提升查询效率。
  • MyBatis系统中默认定义了两级缓存:一级缓存二级缓存
    • 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)
    • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
    • 为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

1、一级缓存

  • 一级缓存也叫本地缓存:
    • 与数据库同一次会话期间查询到的数据会放在本地缓存中。
    • 以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库。
    • sqlSession开启就缓存到本地了
    • 一级缓存容易失效
      • 查询不同的数据就会更新缓存,导致失效
      • 执行增删改查时会改变原来的数据,也会导致缓存失效
      • 查询不同的Mapper.xml
      • 手动清理缓存导致失效
    • 查询内容 ```xml <?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">

  1. - 测试
  2. ```java
  3. package com.iflytek.Dao;
  4. import com.iflytek.pojo.User;
  5. import com.iflytek.utils.MybatisUtils_10;
  6. import org.apache.ibatis.annotations.Mapper;
  7. import org.apache.ibatis.session.SqlSession;
  8. import org.junit.Test;
  9. //二级缓存测试多查询事务回滚
  10. public class UserMapperTest {
  11. //1.获取连接对象
  12. SqlSession sqlSession = MybatisUtils_10.getsqlSession();
  13. //2.获取getMapper连接声明
  14. UserMapper mapper= sqlSession.getMapper(UserMapper.class);
  15. @Test
  16. public void queryUserById_Test(){
  17. User user = mapper.queryUserById(1);
  18. System.out.println(user);
  19. //增删改查都会刷新一级缓存机制
  20. System.out.println("-------------------------------------");
  21. sqlSession.close();
  22. User user2 = mapper.queryUserById(1);
  23. System.out.println(user2);
  24. System.out.println(user == user2);
  25. //增删改查都会刷新一级缓存机制
  26. sqlSession.close();
  27. }
  28. }
  • 缓存效果
    MyBatis - 图7
  • 执行查询时,缓存已经生成
  • 缓存失效

    • 执行CRUD即可导致一级缓存失效 ```xml

    update user set name =#{name},pwd=#{pwd},gender=#{gender},height=#{height} where id=#{id}; java package com.iflytek.Dao;

import com.iflytek.pojo.User; import com.iflytek.utils.MybatisUtils_10; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.session.SqlSession; import org.junit.Test;

//二级缓存测试多查询事务回滚 public class UserMapperTest { //1.获取连接对象 SqlSession sqlSession = MybatisUtils_10.getsqlSession();

  1. //2.获取getMapper连接声明
  2. UserMapper mapper= sqlSession.getMapper(UserMapper.class);
  3. @Test
  4. public void queryUserById_Test(){
  5. User user = mapper.queryUserById(1);
  6. System.out.println(user);
  7. //增删改查都会刷新一级缓存机制
  8. mapper.updateUser(new User(2,"三岁","111111","男",180));
  9. System.out.println("-------------------------------------");
  10. sqlSession.close();
  11. User user2 = mapper.queryUserById(1);
  12. System.out.println(user2);
  13. System.out.println(user == user2);
  14. //增删改查都会刷新一级缓存机制
  15. sqlSession.close();
  16. }

}

  1. - 缓存失效<br />![](https://gitee.com/hg14150/blogiamges/raw/master/img/image-20210415195623543.png#crop=0&crop=0&crop=1&crop=1&id=tvQuR&originHeight=572&originWidth=956&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)
  2. - 插入语句插队,导致缓存失效,产生第二次查询,缓存记录清空,所以记录为false
  3. <a name="088daa62"></a>
  4. #### 2、二级缓存
  5. - 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
  6. - 基于namespace级别的缓存,一个名称空间,对应一个二级缓存;
  7. - 工作机制
  8. -
  9. - 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
  10. - 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
  11. - 新的会话查询信息,就可以从二级缓存中获取内容;
  12. - 不同的mapper查出的数据会放在自己对应的缓存(map)中;
  13. - 使用步骤
  14. - 开启全局缓存(mybatis-config.xml
  15. ```xml
  16. <setting name="cacheEnabled" value="true"/>
  • 自定义二级缓存设置
    1. <cache
    2. eviction="FIFO" #创建高级缓存机制,first in first out 先进先出原则
    3. flushInterval="60000" #设置刷新时间
    4. size="512" #设置最大存储对象
    5. readOnly="true" #开启返回只读权限
    6. />
  • 测试 ```java package com.iflytek.Dao;

import com.iflytek.pojo.User; import com.iflytek.utils.MybatisUtils_10; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.session.SqlSession; import org.junit.Test;

//二级缓存测试多查询事务回滚 public class UserMapperTest { //1.获取连接对象 SqlSession sqlSession = MybatisUtils_10.getsqlSession(); SqlSession sqlSession2 = MybatisUtils_10.getsqlSession();

  1. //2.获取getMapper连接声明
  2. UserMapper mapper= sqlSession.getMapper(UserMapper.class);
  3. UserMapper mapper2= sqlSession2.getMapper(UserMapper.class);
  4. @Test
  5. public void queryUserById_Test(){
  6. User user = mapper.queryUserById(1);
  7. System.out.println(user);
  8. //增删改查都会刷新一级缓存机制

// mapper.updateUser(new User(2,”小王”,”111111”,”男”,167)); System.out.println(“——————————————————-“); sqlSession.close();

  1. User user2 = mapper2.queryUserById(1);
  2. System.out.println(user2);
  3. System.out.println(user == user2);
  4. //增删改查都会刷新一级缓存机制
  5. sqlSession2.close();
  6. }

}

  1. - 缓存效果<br />![](https://gitee.com/hg14150/blogiamges/raw/master/img/image-20210415204236842.png#crop=0&crop=0&crop=1&crop=1&id=oVRbb&originHeight=494&originWidth=884&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)
  2. - 两次查询只有一次记录,证明二级缓存已经生效
  3. - 总结
  4. - 只要开启了二级缓存,我们在同一个Mapper中的查询,可以在二级缓存中拿到数据
  5. - 查出的数据都会被默认先放在一级缓存中
  6. - 只有会话提交或者关闭以后,一级缓存中的数据才会转到二级缓存中
  7. <a name="fd1d32b4"></a>
  8. ## 三、MyBatis-Plus
  9. <a name="c19cae35"></a>
  10. ### 3.1、快速入门MyBats-Plus
  11. - [MyBatis-Plus (opens new window)](https://github.com/baomidou/mybatis-plus)(简称 MP),在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
  12. - 基友搭配,效率翻倍。
  13. > 特性
  14. - **无侵入**:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  15. - **损耗小**:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  16. - **强大的 CRUD 操作**:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  17. - **支持 Lambda 形式调用**:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  18. - **支持主键自动生成**:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  19. - **支持 ActiveRecord 模式**:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  20. - **支持自定义全局通用操作**:支持全局通用方法注入( Write once, use anywhere
  21. - **内置代码生成器**:采用代码或者 Maven 插件可快速生成 Mapper Model Service Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  22. - **内置分页插件**:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  23. - **分页插件支持多种数据库**:支持 MySQLMariaDBOracleDB2H2HSQLSQLitePostgreSQLServer 等多种数据库
  24. - **内置性能分析插件**:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  25. - **内置全局拦截插件**:提供全表 delete update 操作智能分析阻断,也可自定义拦截规则,预防误操作
  26. > 框架结构
  27. ![](https://gitee.com/hg14150/blogiamges/raw/master/img/image-20210415212019187.png#crop=0&crop=0&crop=1&crop=1&id=SVlp0&originHeight=614&originWidth=1062&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)
  28. <a name="c37031af"></a>
  29. #### 3.1.1、快速搭建环境
  30. <a name="d3277b01"></a>
  31. ###### 1、初始化Spring-Boot工程 [Spring Initializer (opens new window)](https://start.spring.io/)
  32. <a name="bc6c489e"></a>
  33. ###### 2、导入依赖
  34. ```xml
  35. <dependencies>
  36. <dependency>
  37. <groupId>org.springframework.boot</groupId>
  38. <artifactId>spring-boot-starter-web</artifactId>
  39. </dependency>
  40. <dependency>
  41. <groupId>org.springframework.boot</groupId>
  42. <artifactId>spring-boot-starter-test</artifactId>
  43. <scope>test</scope>
  44. </dependency>
  45. <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
  46. <dependency>
  47. <groupId>mysql</groupId>
  48. <artifactId>mysql-connector-java</artifactId>
  49. <version>5.1.47</version>
  50. </dependency>
  51. <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
  52. <dependency>
  53. <groupId>org.projectlombok</groupId>
  54. <artifactId>lombok</artifactId>
  55. <version>1.18.12</version>
  56. <scope>provided</scope>
  57. </dependency>
  58. <!--mybaits-plus-->
  59. <dependency>
  60. <groupId>com.baomidou</groupId>
  61. <artifactId>mybatis-plus-boot-starter</artifactId>
  62. <version>3.0.5</version>
  63. </dependency>
  64. <dependency>
  65. <groupId>javax.xml.bind</groupId>
  66. <artifactId>jaxb-api</artifactId>
  67. <version>2.3.0</version>
  68. </dependency>
  69. <dependency>
  70. <groupId>com.sun.xml.bind</groupId>
  71. <artifactId>jaxb-impl</artifactId>
  72. <version>2.3.0</version>
  73. </dependency>
  74. <dependency>
  75. <groupId>com.sun.xml.bind</groupId>
  76. <artifactId>jaxb-core</artifactId>
  77. <version>2.3.0</version>
  78. </dependency>
  79. <dependency>
  80. <groupId>javax.activation</groupId>
  81. <artifactId>activation</artifactId>
  82. <version>1.1.1</version>
  83. </dependency>

3、连接配置
  1. #数据库连接配置
  2. spring.datasource.driver-class-name=com.mysql.jdbc.Driver
  3. spring.datasource.url=jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=UTF-8&useSSL=false
  4. spring.datasource.username=root
  5. spring.datasource.password=123456
  6. #日志配置,默认日志支持
  7. mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

4、使用
  • 在配置完实体类接口后要在主方法上添加扫描包,@MapperScan("com.iflytek.mapper") ```java package com.iflytek;

import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;

@MapperScan(“com.iflytek.mapper”) @SpringBootApplication public class MybatisPlus1Application { public static void main(String[] args) { SpringApplication.run(MybatisPlus1Application.class, args); } }

  1. - `BaseMapper<User>`的使用
  2. - xxxMapper.java接口中继承 **BaseMapper**父类,可以省略所以简单SQLCRUD语句,范型是SQL操作需要使用的查询范型,增加后SQL操作中将不需要再手动添加
  3. ```java
  4. public interface UserMapper extends BaseMapper<Person> {
  5. void selectList();
  6. }
  • 测试 ```java package com.iflytek;

import com.iflytek.mapper.UserMapper; import com.iflytek.pojo.Person; import org.apache.catalina.User; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest class MybatisPlus1ApplicationTests {

  1. @Autowired
  2. private UserMapper userMapper;
  3. @Test
  4. void contextLoads() {
  5. List<Person> personList = userMapper.selectList(null);
  6. personList.forEach(System.out::println);
  7. }

}

  1. - 结果<br />![](https://gitee.com/hg14150/blogiamges/raw/master/img/image-20210416193459291.png#crop=0&crop=0&crop=1&crop=1&id=XQfiN&originHeight=587&originWidth=1416&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)
  2. <a name="7121e0e2"></a>
  3. ### 3.2、CRUD高阶处理
  4. > 实体类接口继承了**BaseMapper**父类,简单SQL语句可省不写
  5. <a name="77933ad0"></a>
  6. #### 3.2.1、CURUD简单操作
  7. - **Insert插入**
  8. - 测试
  9. ```java
  10. //测试数据插入
  11. @Test
  12. public void InsertTest(){
  13. Person person = new Person();
  14. person.setName("二哈");
  15. person.setAge(18);
  16. person.setEmail("123456@qq.com");
  17. int insert = userMapper.insert(person);
  18. System.out.println(insert);
  19. System.out.println(person);
  20. }
  • 结果
    MyBatis - 图8
    • Update更新
  • 测试
    1. //测试数据更新
    2. @Test
    3. public void UpdataTest(){
    4. Person person = new Person();
    5. person.setId(6L);
    6. person.setName("小黄");
    7. person.setAge(18);
    8. person.setEmail("11445522@qq.com");
    9. int update = userMapper.updateById(person);
    10. System.out.println(update);
    11. System.out.println(person);
    12. }
  • 结果
    MyBatis - 图9
    • Delete删除
  • 测试
    1. //测试数据删除
    2. @Test
    3. public void DeleteTest(){
    4. Person person = new Person();
    5. person.setId(5L);
    6. int delete = userMapper.deleteById(person);
    7. System.out.println(delete);
    8. System.out.println(person);
    9. }
  • 结果
    MyBatis - 图10
    • Select查询
  • 测试1,测试多个id的数据
    1. //多数据查询
    2. @Test
    3. public void SelectByIdTest(){
    4. List<Person> personList = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
    5. System.out.println(personList);
    6. }
  • 结果1
    MyBatis - 图11
  • 测试2,条件查询,使用万能的Map更加方便

    1. //条件查询
    2. @Test
    3. public void SelectByOther(){
    4. HashMap<Object, Object> map = new HashMap<>();
    5. //定义SQL
    6. map.put("name","李四");
    7. List<Person> persons= userMapper.selectByMap(map);
    8. System.out.println(persons);
    9. }
  • 结果2
    MyBatis - 图12

3.2.2、雪花算法及主键策略

3.2.2.1、雪花算法
  • snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。
  • 最常见的方式。利用数据库,全数据库唯一。
    • 优点:
      1)简单,代码方便,性能可以接受。
      2)数字ID天然排序,对分页或者需要排序的结果很有帮助。
    • 缺点:
      1)不同数据库语法和实现不同,数据库迁移的时候或多数据库版本支持的时候需要处理。
      2)在单个数据库或读写分离或一主多从的情况下,只有一个主库可以生成,有单点故障的风险。
      3)在性能达不到要求的情况下,比较难于扩展。
      4)如果遇见多个系统需要合并或者涉及到数据迁移会相当痛苦。
      5)分表分库的时候会有麻烦。
  • id自动填充的阵营里,还有UUID,Rediszookeeper等都能达到唯一标准的效果
  • 雪花算法的实现

    1. public class IdWorker{
    2. //下面两个每个5位,加起来就是10位的工作机器id
    3. private long workerId; //工作id
    4. private long datacenterId; //数据id
    5. //12位的序列号
    6. private long sequence;
    7. public IdWorker(long workerId, long datacenterId, long sequence){
    8. // sanity check for workerId
    9. if (workerId > maxWorkerId || workerId < 0) {
    10. throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0",maxWorkerId));
    11. }
    12. if (datacenterId > maxDatacenterId || datacenterId < 0) {
    13. throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0",maxDatacenterId));
    14. }
    15. System.out.printf("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d",
    16. timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId);
    17. this.workerId = workerId;
    18. this.datacenterId = datacenterId;
    19. this.sequence = sequence;
    20. }
    21. //初始时间戳
    22. private long twepoch = 1288834974657L;
    23. //长度为5位
    24. private long workerIdBits = 5L;
    25. private long datacenterIdBits = 5L;
    26. //最大值
    27. private long maxWorkerId = -1L ^ (-1L << workerIdBits);
    28. private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
    29. //序列号id长度
    30. private long sequenceBits = 12L;
    31. //序列号最大值
    32. private long sequenceMask = -1L ^ (-1L << sequenceBits);
    33. //工作id需要左移的位数,12位
    34. private long workerIdShift = sequenceBits;
    35. //数据id需要左移位数 12+5=17位
    36. private long datacenterIdShift = sequenceBits + workerIdBits;
    37. //时间戳需要左移位数 12+5+5=22位
    38. private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
    39. //上次时间戳,初始值为负数
    40. private long lastTimestamp = -1L;
    41. public long getWorkerId(){
    42. return workerId;
    43. }
    44. public long getDatacenterId(){
    45. return datacenterId;
    46. }
    47. public long getTimestamp(){
    48. return System.currentTimeMillis();
    49. }
    50. //下一个ID生成算法
    51. public synchronized long nextId() {
    52. long timestamp = timeGen();
    53. //获取当前时间戳如果小于上次时间戳,则表示时间戳获取出现异常
    54. if (timestamp < lastTimestamp) {
    55. System.err.printf("clock is moving backwards. Rejecting requests until %d.", lastTimestamp);
    56. throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds",
    57. lastTimestamp - timestamp));
    58. }
    59. //获取当前时间戳如果等于上次时间戳(同一毫秒内),则在序列号加一;否则序列号赋值为0,从0开始。
    60. if (lastTimestamp == timestamp) {
    61. sequence = (sequence + 1) & sequenceMask;
    62. if (sequence == 0) {
    63. timestamp = tilNextMillis(lastTimestamp);
    64. }
    65. } else {
    66. sequence = 0;
    67. }
    68. //将上次时间戳值刷新
    69. lastTimestamp = timestamp;
    70. /**
    71. * 返回结果:
    72. * (timestamp - twepoch) << timestampLeftShift) 表示将时间戳减去初始时间戳,再左移相应位数
    73. * (datacenterId << datacenterIdShift) 表示将数据id左移相应位数
    74. * (workerId << workerIdShift) 表示将工作id左移相应位数
    75. * | 是按位或运算符,例如:x | y,只有当x,y都为0的时候结果才为0,其它情况结果都为1。
    76. * 因为个部分只有相应位上的值有意义,其它位上都是0,所以将各部分的值进行 | 运算就能得到最终拼接好的id
    77. */
    78. return ((timestamp - twepoch) << timestampLeftShift) |
    79. (datacenterId << datacenterIdShift) |
    80. (workerId << workerIdShift) |
    81. sequence;
    82. }
    83. //获取时间戳,并与上次时间戳比较
    84. private long tilNextMillis(long lastTimestamp) {
    85. long timestamp = timeGen();
    86. while (timestamp <= lastTimestamp) {
    87. timestamp = timeGen();
    88. }
    89. return timestamp;
    90. }
    91. //获取系统时间戳
    92. private long timeGen(){
    93. return System.currentTimeMillis();
    94. }
    95. //---------------测试---------------
    96. public static void main(String[] args) {
    97. IdWorker worker = new IdWorker(1,1,1);
    98. for (int i = 0; i < 30; i++) {
    99. System.out.println(worker.nextId());
    100. }
    101. }
    102. }

3.2.2.2、主键生成策略
  • 在java层面的主键生成策略主要依赖于TableID注解的方法和属性
    1. @TableId(type = IdType.AUTO)
    2. private Long id;
  • TableId基础方法 ```java IdType type() default IdType.NONE;

public enum IdType { AUTO(0), //主键自增,数据库id必须设置自增,不然会报错 NONE(1), //不使用注解 INPUT(2), //手动输入 ID_WORKER(3), //全局唯一ID UUID(4), //生成UUID ID_WORKER_STR(5); //截取字符串

  1. private int key;
  2. private IdType(int key) {
  3. this.key = key;
  4. }
  5. public int getKey() {
  6. return this.key;
  7. }

}

  1. <a name="a49693da"></a>
  2. ##### 3.2.2.3、自动填充
  3. - 自动填充主要用于数据创建时间、数据修改时间等出事操作
  4. - 在阿里巴巴开发手册里要求使用
  5. - gmt_create
  6. - gmt_modified
  7. - 方式一:数据库层面的自动填充(**工作中不建议使用**)
  8. - create_time 自动填充创建时间
  9. - update_time 自动填充修改时间<br />![](https://gitee.com/hg14150/blogiamges/raw/master/img/image-20210416205428966.png#crop=0&crop=0&crop=1&crop=1&id=THnLY&originHeight=327&originWidth=1306&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)
  10. - 同步实体类
  11. ```java
  12. @Data
  13. @NoArgsConstructor
  14. @AllArgsConstructor
  15. @ToString
  16. public class Person implements Serializable {
  17. @TableId(type = IdType.AUTO)
  18. private Long id;
  19. private String name;
  20. private int age;
  21. private String email;
  22. private Date createTime;
  23. private Date updateTime;
  24. }
  • 测试

    1. //测试数据插入
    2. @Test
    3. public void InsertTest(){
    4. Person person = new Person();
    5. person.setName("陈皮");
    6. person.setAge(18);
    7. person.setEmail("123456@qq.com");
    8. int insert = userMapper.insert(person);
    9. System.out.println(insert);
    10. System.out.println(person);
    11. }
    12. //测试数据更新
    13. @Test
    14. public void UpdataTest(){
    15. Person person = new Person();
    16. person.setId(6L);
    17. person.setName("老狗");
    18. person.setAge(18);
    19. person.setEmail("11445521232@qq.com");
    20. int update = userMapper.updateById(person);
    21. System.out.println(update);
    22. System.out.println(person);
    23. }
  • 结果
    MyBatis - 图13
    • 方法二:java层面的自动填充
  • Java层面的自动填充操作需要在实体类上添加注解,一般企业级开发建议操作
    MyBatis - 图14
  • TableFild介绍 ```java //默认为null String value() default “”;

public enum FieldFill { DEFAULT, //默认使用 INSERT, //插入时使用 UPDATE, //更新时使用 INSERT_UPDATE;//插入和更新时使用

  1. private FieldFill() {
  2. }

}

  1. - 使用
  2. 1. 添加注解
  3. ```java
  4. /**
  5. * 字段自动填充
  6. */
  7. @TableField(fill = FieldFill.INSERT)
  8. private Date createTime;
  9. @TableField(fill = FieldFill.INSERT_UPDATE)
  10. private Date updateTime;
  1. 2. 处理注解配置,新建一个`Handler.java`类实现`MetaObjectHandler`父类
  1. package com.iflytek.Config;
  2. import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.apache.ibatis.reflection.MetaObject;
  5. import org.springframework.stereotype.Component;
  6. import java.util.Date;
  7. /**
  8. * @author 黄果
  9. * @date2021/4/16 21:07
  10. * @title 现世安稳,岁月静好,佛祖保佑,永无bug!
  11. */
  12. @Slf4j
  13. @Component //添加到IOC容器里
  14. public class Handler implements MetaObjectHandler {
  15. @Override
  16. public void insertFill(MetaObject metaObject) {
  17. //插入时自动填充
  18. this.setFieldValByName("createTime",new Date(),metaObject);
  19. log.info("执行插入填充");
  20. }
  21. @Override
  22. public void updateFill(MetaObject metaObject) {
  23. //更新时自动填充
  24. this.setFieldValByName("updateTime",new Date(),metaObject);
  25. log.info("执行更新填充");
  26. }
  27. }
  1. 3. 测试
  1. //测试数据插入
  2. @Test
  3. public void InsertTest(){
  4. Person person = new Person();
  5. person.setName("八戒");
  6. person.setAge(18);
  7. person.setEmail("369820440@qq.com");
  8. int insert = userMapper.insert(person);
  9. System.out.println(insert);
  10. System.out.println(person);
  11. }
  12. //测试数据更新
  13. @Test
  14. public void UpdataTest(){
  15. Person person = new Person();
  16. person.setId(5L);
  17. person.setName("小王");
  18. person.setAge(18);
  19. person.setEmail("11445521232@qq.com");
  20. int update = userMapper.updateById(person);
  21. System.out.println(update);
  22. System.out.println(person);
  23. }
  1. 4. 结果<br />![](https://gitee.com/hg14150/blogiamges/raw/master/img/image-20210416212140244.png#crop=0&crop=0&crop=1&crop=1&id=u96nO&originHeight=288&originWidth=1426&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)<br />![](https://gitee.com/hg14150/blogiamges/raw/master/img/image-20210416212235542.png#crop=0&crop=0&crop=1&crop=1&id=USPMQ&originHeight=423&originWidth=1556&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)<br />![](https://gitee.com/hg14150/blogiamges/raw/master/img/image-20210416212342113.png#crop=0&crop=0&crop=1&crop=1&id=TokfH&originHeight=328&originWidth=1265&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)

3.3、插件应用分析

3.3.1、乐观锁处理

  • 乐观锁
    • 平时不加锁,出问题了在更新测试,容错率高
  • 悲观锁
    • 新建数据时即加锁,只要一出问题就锁定数据,过于严谨

乐观锁实现

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败 ```

    乐观锁:1、先查询,获取版本号 version=1

A

update person set name =’小黄’ ,version =version + 1 where id = 2 and version =1

B

线程抢先完成,version =2 导致A失败

update person set name =’春花’ ,version =version + 1 where id = 2 and version =1

  1. - 测试乐观锁插件
  2. 1. 添加数据库字段<br />![](https://gitee.com/hg14150/blogiamges/raw/master/img/image-20210416220011584.png#crop=0&crop=0&crop=1&crop=1&id=AQh8j&originHeight=308&originWidth=1263&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)
  3. 1. 添加实体类字段及注解
  4. ```java
  5. /**
  6. * 添加乐观锁注解
  7. */
  8. @Version
  9. private int version;
  1. 注册乐观锁插件,新建MyBatisPlusConfig.java类

    1. //注册乐观锁插件
    2. @Bean
    3. public OptimisticLockerInterceptor optimisticLockerInterceptor() {
    4. return new OptimisticLockerInterceptor();
    5. }
    6. }
  1. 测试

    1. //测试乐观锁——成功
    2. @Test
    3. public void OptimisticLockTest(){
    4. //查询用户信息
    5. Person person = userMapper.selectById(1L);
    6. //修改数据
    7. person.setName("悟空");
    8. person.setAge(25);
    9. //执行修改
    10. int update = userMapper.updateById(person);
    11. System.out.println(update);
    12. System.out.println(person);
    13. }
    14. //测试乐观锁——成功
    15. @Test
    16. public void OptimisticLockTest2(){
    17. //查询用户信息
    18. //线程1
    19. Person person = userMapper.selectById(1L);
    20. //修改数据
    21. person.setName("悟空");
    22. person.setAge(25);
    23. //线程2插队
    24. //线程1
    25. Person person2 = userMapper.selectById(1L);
    26. //修改数据
    27. person2.setName("盲僧");
    28. person2.setAge(28);
    29. //执行线程2插队修改
    30. int update2 = userMapper.updateById(person2);
    31. System.out.println(update2);
    32. System.out.println(person2);
    33. //执行线程1修改
    34. int update = userMapper.updateById(person);
    35. System.out.println(update);
    36. System.out.println(person);
    37. }
  1. 结果
    成功
    MyBatis - 图15
    失败
    MyBatis - 图16
    MyBatis - 图17
  2. 数据显示
    MyBatis - 图18

3.3.2、分页的实现

分页是一个最热的业务基础,几乎所有的网站运用都要用到,经常使用的分页技术以下所示

  • Limit实现分页
  • RowBounds实现分页
  • MyBatis-plus实现分页,本质还是limit

MyBatis-Plus分页的使用

  • 注册分页插件(MyBatisPlusConfig.java
    1. //注册分页插件
    2. @Bean
    3. public PaginationInterceptor paginationInterceptor() {
    4. PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
    5. // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
    6. // paginationInterceptor.setOverflow(false);
    7. // 设置最大单页限制数量,默认 500 条,-1 不受限制
    8. // paginationInterceptor.setLimit(500);
    9. // 开启 count 的 join 优化,只针对部分 left join
    10. // paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
    11. return paginationInterceptor;
    12. }
  • 测试
    1. @Test
    2. public void PageTest(){
    3. //定义当前查询页的起始id和大小
    4. Page<Person> page = new Page<>(1,3);
    5. IPage<Person> personIPage = userMapper.selectPage(page, null);
    6. System.out.println(personIPage.getRecords());
    7. }
  • 结果
    MyBatis - 图19

3.3.3、删除操作

1、普通删除
  • 测试1,通过id删除多个数据
    1. //通过id删除多个数据
    2. @Test
    3. public void DeleteByBatchIdTest(){
    4. int deleteBatchIds = userMapper.deleteBatchIds(Arrays.asList(1, 2));
    5. System.out.println(deleteBatchIds);
    6. }
  • 结果1
    MyBatis - 图20
  • 测试2,通过map删除数据
    1. //通过Map删除数据
    2. @Test
    3. public void DeleteByMapest(){
    4. HashMap<String, Object> map = new HashMap<>();
    5. map.put("name","老狗");
    6. int deleteByMap = userMapper.deleteByMap(map);
    7. System.out.println(deleteByMap);
    8. }
  • 结果2
    MyBatis - 图21

2、逻辑删除
  • 物理删除
    • 删除就没有了,从磁盘里摸出数据,不可恢复
  • 逻辑删除
    • 只是逻辑形式上的删除,使用一个变量让数据失效,让用户查询不到数据的的存在,实际上数据并没有真正的删除,依然还存在数据库中

删除操作

  • 增加数据库伪删除字段deleted且默认值为0

MyBatis - 图22

  • 实体类添加字段及注解
    1. /**
    2. * 逻辑删除
    3. */
    4. @TableLogic
    5. private int deleted;
  • 注册逻辑删除插件(MyBatisPlusConfig.java / application.properties)
    1. //注册逻辑删除插件
    2. @Bean
    3. public ISqlInjector sqlInjector(){
    4. return new LogicSqlInjector();
    5. }
  • 测试
    1. //通过Map删除多个数据,执行逻辑删除
    2. @Test
    3. public void DeleteByMapest(){
    4. HashMap<String, Object> map = new HashMap<>();
    5. map.put("id",3);
    6. int deleteByMap = userMapper.deleteByMap(map);
    7. System.out.println(deleteByMap);
    8. }
  • 结果
    MyBatis - 图23

数据显示

MyBatis - 图24

3.3.4、性能分析

用于监管每条数据读写的时间大小,从而反应出性能的优劣程度

  • 注册插件(MyBatisPlusConfig.java)
    1. //注册性能插件
    2. @Bean
    3. // 设置 dev test 环境开启
    4. @Profile({"dev","test"})
    5. public PerformanceInterceptor performanceInterceptor() {
    6. PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
    7. //ms,超过此处设置的ms则sql不执行
    8. performanceInterceptor.setMaxTime(50);
    9. //是否格式化SQL语句
    10. performanceInterceptor.setFormat(true);
    11. return performanceInterceptor;
    12. }
  • 开启测试环境
    1. #设置开发环境
    2. spring.profiles.active=dev
  • 测试
    1. //测试查询全部数据
    2. @Test
    3. void selectListTest() {
    4. List<Person> personList = userMapper.selectList(null);
    5. personList.forEach(System.out::println);
    6. }
  • 结果1,最大时间过小,待优化
    MyBatis - 图25
  • 结果2,时间适当,最优查询
    MyBatis - 图26

3.3.5、条件构造器Wrapper

  • 这是一个敏捷开发的重要工具,一切为了简化而生是它的使命
    | Wapper | Maens | Users | | —- | —- | —- | | eq | = | eq("name", "老王")
    name = '老王' | | ne | != | ne("name", "老王")
    name != '老王' | | gt | > | gt("age", 18)
    age > 18 | | lt | < | lt("age", 18)
    age < 18 | | between | 1 and 2 | between("age", 18, 30)
    age between 18 and 30 | | notBetween | not 1 and 2 | notBetween("age", 18, 30)
    age not between 18 and 30 | | like | 模糊查询 | likeRight("name", "王")
    name like '王%' | | nolike | 模糊查询外的数据 | notLike("name", "王")
    name not like '%王%' | | likeLeft | 左模糊查询 | likeRight("name", "王")
    name like '王%' | | likeRight | 右模糊查询 | likeLeft("name", "王")
    name like '%王' | | isNull | 字段为空 | isNull("name")
    name is null | | isNotNull | 字段不为空 | isNotNull("name")
    name is not null | | in | 字段内查询 | in("age",{1,2,3})
    age in (1,2,3) | | inSql | 嵌套查询 | inSql("id", "select id from table where id < 3")
    ,id in (select id from table where id < 3) | | groupBy | 字段分组 | groupBy("id", "name")
    group by id,name | | orderByAsc | 升序 | orderByAsc(“id”)
    order by id ASC| | orderByDesc | 降序 |orderByDesc(“id”)<br />,order by id DESC| | orderBy | 字段排序 |orderBy(true, true, “id”, “name”)<br />,order by id ASC,name ASC| | having | 函数having(sql) |having(“sum(age) > 10”)<br />,having sum(age) > 10` |

  • 测试1

    1. //测试查询全部数据
    2. @Test
    3. public void selectListTest() {
    4. //查询name不为空的,邮箱不为空的用户
    5. QueryWrapper<Person> wapper = new QueryWrapper<>();
    6. wapper.isNotNull("name").isNotNull("email").ge("age",20);
    7. userMapper.selectList(wapper);
    8. System.out.println(wapper);
    9. }
  • 结果1
    MyBatis - 图27
  • 测试2
    1. //查询年龄在20到25之间的数据
    2. @Test
    3. public void betweenTest(){
    4. QueryWrapper<Person> wapper = new QueryWrapper<>();
    5. wapper.between("age", 20, 25);
    6. int count=userMapper.selectCount(wapper);
    7. List<Person> personList = userMapper.selectList(wapper);
    8. System.out.println(count);
    9. System.out.println(personList);
    10. }
  • 结果2
    MyBatis - 图28
  • 测试3
    1. //查询指定数据
    2. @Test
    3. public void EqTest(){
    4. QueryWrapper<Person> wappers = new QueryWrapper<>();
    5. QueryWrapper<Person> eq = wappers.eq("name", "八戒");
    6. Person person = userMapper.selectOne(eq);
    7. System.out.println(person);
    8. }
  • 结果3
    MyBatis - 图29
  • 测试4
    1. //模糊查询不包含指定内容的数据
    2. @Test
    3. public void noLikeTest(){
    4. QueryWrapper<Person> wapper = new QueryWrapper<>();
    5. wapper.notLike("name","小").likeRight("email","t");
    6. List<Map<String, Object>> maps = userMapper.selectMaps(wapper);
    7. maps.forEach(System.out::println);
    8. }
  • 结果4
    MyBatis - 图30
  • 测试5
    1. //模糊自查询
    2. @Test
    3. public void selectTest(){
    4. QueryWrapper<Person> wapper = new QueryWrapper<>();
    5. wapper.inSql("id","select id from person where id>6");
    6. List<Person> personList = userMapper.selectList(wapper);
    7. personList.forEach(System.out::println);
    8. }
  • 结果5
    MyBatis - 图31
  • 测试6
    1. //排序测试
    2. @Test
    3. public void oderbyscTest(){
    4. QueryWrapper<Person> wapper = new QueryWrapper<>();
    5. wapper.orderByDesc("id");
    6. List<Person> personList = userMapper.selectList(wapper);
    7. personList.forEach(System.out::println);
    8. }
  • 结果6
    MyBatis - 图32
  • 开发中使用能在一定程度上提高工作效率

3.5、MyBatis-Plus逆向工程

这才是重点

1、创建springBoot工程

工程搭建步骤请看这里

2、导入依赖
  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-web</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.boot</groupId>
  8. <artifactId>spring-boot-starter-test</artifactId>
  9. <scope>test</scope>
  10. </dependency>
  11. <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
  12. <dependency>
  13. <groupId>mysql</groupId>
  14. <artifactId>mysql-connector-java</artifactId>
  15. <version>5.1.47</version>
  16. </dependency>
  17. <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
  18. <dependency>
  19. <groupId>org.projectlombok</groupId>
  20. <artifactId>lombok</artifactId>
  21. <version>1.18.12</version>
  22. <scope>provided</scope>
  23. </dependency>
  24. <!--mybaits-plus-->
  25. <dependency>
  26. <groupId>com.baomidou</groupId>
  27. <artifactId>mybatis-plus-boot-starter</artifactId>
  28. <version>3.0.5</version>
  29. </dependency>
  30. <dependency>
  31. <groupId>javax.xml.bind</groupId>
  32. <artifactId>jaxb-api</artifactId>
  33. <version>2.3.0</version>
  34. </dependency>
  35. <dependency>
  36. <groupId>com.sun.xml.bind</groupId>
  37. <artifactId>jaxb-impl</artifactId>
  38. <version>2.3.0</version>
  39. </dependency>
  40. <dependency>
  41. <groupId>com.sun.xml.bind</groupId>
  42. <artifactId>jaxb-core</artifactId>
  43. <version>2.3.0</version>
  44. </dependency>
  45. <dependency>
  46. <groupId>javax.activation</groupId>
  47. <artifactId>activation</artifactId>
  48. <version>1.1.1</version>
  49. </dependency>
  50. <dependency>
  51. <groupId>com.baomidou</groupId>
  52. <artifactId>mybatis-plus-generator</artifactId>
  53. <version>3.1.0</version>
  54. </dependency>
  55. <dependency>
  56. <groupId>org.freemarker</groupId>
  57. <artifactId>freemarker</artifactId>
  58. <version>2.3.31</version>
  59. </dependency>
  60. <dependency>
  61. <groupId>org.apache.velocity</groupId>
  62. <artifactId>velocity-engine-core</artifactId>
  63. <version>2.3</version>
  64. </dependency>
  65. </dependencies>

3、配置数据库连接(application.properties)
  1. #设置开发环境
  2. spring.profiles.active=dev
  3. #数据库连接配置
  4. spring.datasource.driver-class-name=com.mysql.jdbc.Driver
  5. spring.datasource.url=jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=UTF-8&useSSL=false
  6. spring.datasource.username=root
  7. spring.datasource.password=123456
  8. #日志配置
  9. mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
  10. #配置逻辑删除
  11. mybatis-plus.global-config.db-config.logic-delete-value=1
  12. mybatis-plus.global-config.db-config.logic-not-delete-value=0

4、配置插件注册(MyBatisPlusConfig.java)
  1. //注册乐观锁插件
  2. @Bean
  3. public OptimisticLockerInterceptor optimisticLockerInterceptor() {
  4. return new OptimisticLockerInterceptor();
  5. }
  6. //注册分页插件
  7. @Bean
  8. public PaginationInterceptor paginationInterceptor() {
  9. PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
  10. // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
  11. // paginationInterceptor.setOverflow(false);
  12. // 设置最大单页限制数量,默认 500 条,-1 不受限制
  13. // paginationInterceptor.setLimit(500);
  14. // 开启 count 的 join 优化,只针对部分 left join
  15. // paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
  16. return paginationInterceptor;
  17. }
  18. //注册逻辑删除插件
  19. @Bean
  20. public ISqlInjector sqlInjector(){
  21. return new LogicSqlInjector();
  22. }
  23. //注册性能插件
  24. @Bean
  25. // 设置 dev test 环境开启
  26. @Profile({"dev","test"})
  27. public PerformanceInterceptor performanceInterceptor() {
  28. PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
  29. performanceInterceptor.setMaxTime(50);
  30. //ms,超过此处设置的ms则sql不执行
  31. //performanceInterceptor.setFormat(true);
  32. return performanceInterceptor;
  33. }

5、配置自动生成类(CodeGenerator.java)

1、控制台输入
  1. public class CodeGenerator {
  2. //0、读取控制台内容
  3. public static String scanner(String tip) {
  4. Scanner scanner = new Scanner(System.in);
  5. StringBuilder help = new StringBuilder();
  6. help.append("请输入" + tip + ":");
  7. System.out.println(help.toString());
  8. if (scanner.hasNext()) {
  9. String ipt = scanner.next();
  10. if (StringUtils.isNotBlank(ipt)) {
  11. return ipt;
  12. }
  13. }
  14. throw new MybatisPlusException("请输入正确的" + tip + "!");
  15. }
  16. public static void main(String[] args) {
  17. //1、获取代码生成器对象
  18. AutoGenerator mpg = new AutoGenerator();
  19. //2、全局配置
  20. GlobalConfig gc = new GlobalConfig();
  21. //获取用户目录
  22. String projectPath = System.getProperty("user.dir");
  23. //代码生成路径
  24. gc.setOutputDir(projectPath + "/src/main/java");
  25. //作者信息
  26. gc.setAuthor("黄果");
  27. gc.setOpen(false);
  28. //生成ID类型
  29. gc.setIdType(IdType.AUTO);
  30. gc.setDateType(DateType.ONLY_DATE);
  31. gc.setFileOverride(true);
  32. //去掉Servce前缀
  33. gc.setServiceImplName("%sService");
  34. mpg.setGlobalConfig(gc);
  35. //3、数据源配置
  36. DataSourceConfig dsc = new DataSourceConfig();
  37. dsc.setUrl("jdbc:mysql://localhost:3306/school?useUnicode=true&useSSL=false&characterEncoding=utf8");
  38. dsc.setDriverName("com.mysql.jdbc.Driver");
  39. dsc.setUsername("root");
  40. dsc.setPassword("123456");
  41. dsc.setDbType(DbType.MYSQL);
  42. mpg.setDataSource(dsc);
  43. //4、包配置
  44. PackageConfig pc = new PackageConfig();
  45. //设置模块名 com.iflytek.project
  46. //pc.setModuleName("project"); //没有第0步时此代码必写
  47. pc.setModuleName(scanner("模块名")); //第0步省略时此代码可删
  48. //5、设置工程名
  49. pc.setParent("com.iflytek");
  50. //设置包名
  51. pc.setEntity("entity");
  52. pc.setMapper("mapper");
  53. pc.setService("service");
  54. pc.setController("controller");
  55. mpg.setPackageInfo(pc);
  56. //6、自定义配置
  57. InjectionConfig cfg = new InjectionConfig() {
  58. @Override
  59. public void initMap() {
  60. // to do nothing
  61. }
  62. };
  63. //7、如果模板引擎是 freemarker
  64. String templatePath = "/templates/mapper.xml.ftl";
  65. //8、自定义输出配置
  66. List<FileOutConfig> focList = new ArrayList<>();
  67. // 自定义配置会被优先输出
  68. focList.add(new FileOutConfig(templatePath) {
  69. @Override
  70. public String outputFile(TableInfo tableInfo) {
  71. // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
  72. return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
  73. + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
  74. }
  75. });
  76. cfg.setFileOutConfigList(focList);
  77. mpg.setCfg(cfg);
  78. //9、配置模板
  79. TemplateConfig templateConfig = new TemplateConfig();
  80. templateConfig.setXml(null);
  81. mpg.setTemplate(templateConfig);
  82. //10、策略配置
  83. StrategyConfig strategy = new StrategyConfig();
  84. //数据库表名优先映射,配置
  85. strategy.setInclude("person");
  86. //下划线转驼峰命名的策略
  87. strategy.setNaming(NamingStrategy.underline_to_camel);
  88. //数据库命名规则
  89. strategy.setColumnNaming(NamingStrategy.underline_to_camel);
  90. //自动生成lombok注解
  91. strategy.setEntityLombokModel(true);
  92. //自动添加控制结构
  93. strategy.setRestControllerStyle(true);
  94. //自动添加逻辑删除策略
  95. strategy.setLogicDeleteFieldName("deleted");
  96. //11、设置自动填充策略
  97. TableFill gmtCreatereate = new TableFill("gmt_create", FieldFill.INSERT);
  98. //设置自动更新时间策略
  99. TableFill gmtModifiedodified = new TableFill("gmt_modified", FieldFill.UPDATE);
  100. //获取自动填充对象
  101. ArrayList<TableFill> tableFills = new ArrayList<>();
  102. //添加填充策略
  103. tableFills.add(gmtCreatereate);
  104. tableFills.add(gmtModifiedodified);
  105. strategy.setTableFillList(tableFills);
  106. //12、设置乐观锁策略
  107. strategy.setVersionFieldName("version");
  108. //设置Restful风格
  109. strategy.setRestControllerStyle(true);
  110. //设置连接请求 http://localhost:8080/hello_id_2
  111. strategy.setControllerMappingHyphenStyle(true);
  112. //第0步省略,此行代码可删
  113. strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
  114. mpg.setStrategy(strategy);
  115. mpg.execute();
  116. }
  117. }

2、无控制台输入
  1. public class CodeGenerator {
  2. public static void main(String[] args) {
  3. //1、获取代码生成器对象
  4. AutoGenerator mpg = new AutoGenerator();
  5. //2、全局配置
  6. GlobalConfig gc = new GlobalConfig();
  7. //获取用户目录
  8. String projectPath = System.getProperty("user.dir");
  9. //代码生成路径
  10. gc.setOutputDir(projectPath + "/src/main/java");
  11. //作者信息
  12. gc.setAuthor("黄果");
  13. gc.setOpen(false);
  14. //生成ID类型
  15. gc.setIdType(IdType.AUTO);
  16. gc.setDateType(DateType.ONLY_DATE);
  17. gc.setFileOverride(true);
  18. //去掉Servce前缀
  19. gc.setServiceImplName("%sService");
  20. mpg.setGlobalConfig(gc);
  21. //3、数据源配置
  22. DataSourceConfig dsc = new DataSourceConfig();
  23. dsc.setUrl("jdbc:mysql://localhost:3306/school?useUnicode=true&useSSL=false&characterEncoding=utf8");
  24. dsc.setDriverName("com.mysql.jdbc.Driver");
  25. dsc.setUsername("root");
  26. dsc.setPassword("123456");
  27. dsc.setDbType(DbType.MYSQL);
  28. mpg.setDataSource(dsc);
  29. //4、包配置
  30. PackageConfig pc = new PackageConfig();
  31. //设置模块名 com.iflytek.project
  32. pc.setModuleName("project"); //没有第0步时此代码必写
  33. //5、设置工程名
  34. pc.setParent("com.iflytek");
  35. //设置包名
  36. pc.setEntity("entity");
  37. pc.setMapper("mapper");
  38. pc.setService("service");
  39. pc.setController("controller");
  40. mpg.setPackageInfo(pc);
  41. //6、策略配置
  42. StrategyConfig strategy = new StrategyConfig();
  43. //数据库表名优先映射,配置
  44. strategy.setInclude("person","account","student","users");
  45. //下划线转驼峰命名的策略
  46. strategy.setNaming(NamingStrategy.underline_to_camel);
  47. //数据库命名规则
  48. strategy.setColumnNaming(NamingStrategy.underline_to_camel);
  49. //自动生成lombok注解
  50. strategy.setEntityLombokModel(true);
  51. //自动添加控制结构
  52. strategy.setRestControllerStyle(true);
  53. //自动添加逻辑删除策略
  54. strategy.setLogicDeleteFieldName("deleted");
  55. //7、设置自动填充策略
  56. TableFill gmtCreatereate = new TableFill("gmt_create", FieldFill.INSERT);
  57. //设置自动更新时间策略
  58. TableFill gmtModifiedodified = new TableFill("gmt_modified", FieldFill.UPDATE);
  59. //获取自动填充对象
  60. ArrayList<TableFill> tableFills = new ArrayList<>();
  61. //添加填充策略
  62. tableFills.add(gmtCreatereate);
  63. tableFills.add(gmtModifiedodified);
  64. strategy.setTableFillList(tableFills);
  65. //8、设置乐观锁策略
  66. strategy.setVersionFieldName("version");
  67. //设置Restful风格
  68. strategy.setRestControllerStyle(true);
  69. //设置连接请求 http://localhost:8080/hello_id_2
  70. strategy.setControllerMappingHyphenStyle(true);
  71. mpg.setStrategy(strategy);
  72. mpg.execute();
  73. }
  74. }

6、生成结果

MyBatis - 图33