zoukankan      html  css  js  c++  java
  • MyBatis Plus

    1.引入

    1.简介

      MyBatis-Plus(简称 MP),是一个 MyBatis 的增强工具包,只做增强不做改变. 为简化开发工作、提高生产率而生,愿景是成为 Mybatis 最好的搭档,就像 魂斗罗 中的 1P、2P,基友搭配,效率
    翻倍,基于mybatis

    2.相关文档

      官方地址:

    http://mp.baomidou.com

    https://mybatis.plus/

      代码发布地址:Github: https://github.com/baomidou/mybatis-plusGitee: https://gitee.com/baomidou/mybatis-plus

      文档发布地址:http://mp.baomidou.com/#/?id=简��%

    3.前置知识

    Mybatis、Spring、Maven

    2.环境搭建

    2.1 准备

    • 表结构
    -- 创建库
    CREATE DATABASE mp;
    -- 使用库
    USE mp;
    -- 创建表
    CREATE TABLE tbl_employee(
     id INT(11) PRIMARY KEY AUTO_INCREMENT,
     last_name VARCHAR(50),
     email VARCHAR(50),
     gender CHAR(1),
     age int
    );
    INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('Tom','tom@zhenqk.com',1,18);
    INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('Tony','jerry@zhenqk.com',0,25);
    INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('Black','black@zhenqk.com',1,20);
    INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('White','white@zhenqk.com',0,30);
    

    用包装类的原因: 每个基本类型的默认值不一样

    • domain
    @Setter
    @Getter
    @ToString
    public class Employee implements Serializable {
        private Integer id;
        private String lastNamprivate;
        String email;
        private Integer gender;
        private Integer age;
    }
    
    

    pom.xml

      <dependencies>
            <!-- mp依赖
                           mybatisPlus 会自动的维护Mybatis 以及MyBatis-spring相关的依赖
                       -->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus</artifactId>
                <version>3.4.0</version>
            </dependency>
    
            <!--junit -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.9</version>
            </dependency>
            <!-- log4j -->
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.17</version>
            </dependency>
            <!-- c3p0 -->
            <dependency>
                <groupId>com.mchange</groupId>
                <artifactId>c3p0</artifactId>
                <version>0.9.5.2</version>
            </dependency>
            <!-- mysql -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.47</version>
            </dependency>
            <!-- spring -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.2.8.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-orm</artifactId>
                <version>5.2.8.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.12</version>
            </dependency>
        </dependencies>
    

    2.mybatis 的整合

    • log4j.xml
    <?xml version="1.0" encoding="UTF-8"?>
            <!DOCTYPE log4j:configuration PUBLIC "-//log4j/log4j Configuration//EN" "log4j.dtd">
    
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
        <!-- 日志输出到控制台 -->
        <appender name="console" class="org.apache.log4j.ConsoleAppender">
            <!-- 日志输出格式 -->
            <layout class="org.apache.log4j.PatternLayout">
                <param name="ConversionPattern" value="[%p][%d{yyyy-MM-dd HH:mm:ss SSS}][%c]-[%m]%n"/>
            </layout>
    
            <!--过滤器设置输出的级别-->
            <filter class="org.apache.log4j.varia.LevelRangeFilter">
                <!-- 设置日志输出的最小级别 -->
                <param name="levelMin" value="INFO"/>
                <!-- 设置日志输出的最大级别 -->
                <param name="levelMax" value="ERROR"/>
            </filter>
        </appender>
    
    
        <!-- 输出日志到文件 -->
        <appender name="fileAppender" class="org.apache.log4j.FileAppender">
            <!-- 输出文件全路径名-->
            <param name="File" value="/data/applogs/own/fileAppender.log"/>
            <!--是否在已存在的文件追加写:默认时true,若为false则每次启动都会删除并重新新建文件-->
            <param name="Append" value="false"/>
            <param name="Threshold" value="INFO"/>
            <!--是否启用缓存,默认false-->
            <param name="BufferedIO" value="false"/>
            <!--缓存大小,依赖上一个参数(bufferedIO), 默认缓存大小8K  -->
            <param name="BufferSize" value="512"/>
            <!-- 日志输出格式 -->
            <layout class="org.apache.log4j.PatternLayout">
                <param name="ConversionPattern" value="[%p][%d{yyyy-MM-dd HH:mm:ss SSS}][%c]-[%m]%n"/>
            </layout>
        </appender>
    
    
        <!-- 输出日志到文件,当文件大小达到一定阈值时,自动备份 -->
        <!-- FileAppender子类 -->
        <appender name="rollingAppender" class="org.apache.log4j.RollingFileAppender">
            <!-- 日志文件全路径名 -->
            <param name="File" value="/data/applogs/RollingFileAppender.log" />
            <!--是否在已存在的文件追加写:默认时true,若为false则每次启动都会删除并重新新建文件-->
            <param name="Append" value="true" />
            <!-- 保存备份日志的最大个数,默认值是:1  -->
            <param name="MaxBackupIndex" value="10" />
            <!-- 设置当日志文件达到此阈值的时候自动回滚,单位可以是KB,MB,GB,默认单位是KB,默认值是:10MB -->
            <param name="MaxFileSize" value="10KB" />
            <!-- 设置日志输出的样式 -->`
            <layout class="org.apache.log4j.PatternLayout">
                <!-- 日志输出格式 -->
                <param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss:SSS}] [%-5p] [method:%l]%n%m%n%n" />
            </layout>
        </appender>
    
    
        <!-- 日志输出到文件,可以配置多久产生一个新的日志信息文件 -->
        <appender name="dailyRollingAppender" class="org.apache.log4j.DailyRollingFileAppender">
            <!-- 文件文件全路径名 -->
            <param name="File" value="/data/applogs/own/dailyRollingAppender.log"/>
            <param name="Append" value="true" />
            <!-- 设置日志备份频率,默认:为每天一个日志文件 -->
            <param name="DatePattern" value="'.'yyyy-MM-dd'.log'" />
    
            <!--每分钟一个备份-->
            <!--<param name="DatePattern" value="'.'yyyy-MM-dd-HH-mm'.log'" />-->
            <layout class="org.apache.log4j.PatternLayout">
                <param name="ConversionPattern" value="[%p][%d{HH:mm:ss SSS}][%c]-[%m]%n"/>
            </layout>
        </appender>
    
    
    
        <!--
            1. 指定logger的设置,additivity是否遵循缺省的继承机制
            2. 当additivity="false"时,root中的配置就失灵了,不遵循缺省的继承机制
            3. 代码中使用Logger.getLogger("logTest")获得此输出器,且不会使用根输出器
        -->
        <logger name="logTest" additivity="false">
            <level value ="INFO"/>
            <appender-ref ref="dailyRollingAppender"/>
        </logger>
    
    
        <!-- 根logger的设置,若代码中未找到指定的logger,则会根据继承机制,使用根logger-->
        <root>
            <appender-ref ref="console"/>
            <appender-ref ref="fileAppender"/>
            <appender-ref ref="rollingAppender"/>
            <appender-ref ref="dailyRollingAppender"/>
        </root>
    
    </log4j:configuration>
    
    
    • mybatis-config.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">
    <configuration>
    
    </configuration>
    
    • applicationContext.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
           xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring
            http://mybatis.org/schema/mybatis-spring-1.2.xsd
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-4.0.xsd
            http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
        <!-- 数据源 -->
    
        <context:property-placeholder location="classpath:jdbc.properties"/>
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value="${druid.driver}"></property>
            <property name="url" value="${druid.url}"></property>
            <property name="username" value="${druid.username}"></property>
            <property name="password" value="${druid.password}"></property>
        </bean>
        <!-- 事务管理器 -->
        <bean id="dataSourceTransactionManager"
              class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
        <!-- 基于注解的事务管理 -->
        <tx:annotation-driven
                transaction-manager="dataSourceTransactionManager"/>
        <!-- 配置 SqlSessionFactoryBean -->
        <bean id="sqlSessionFactoryBean"
              class="org.mybatis.spring.SqlSessionFactoryBean">
            <!-- 数据源 -->
            <property name="dataSource" ref="dataSource"></property>
            <property name="configLocation"
    
                      value="classpath:mybatis-config.xml"></property>
            <!-- 别名处理 -->
            <property name="typeAliasesPackage"
                      value="cn.ccut.domain"></property>
        </bean>
        <!--
        配置 mybatis 扫描 mapper 接口的路径
        -->
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage"
                      value="cn.ccut.mapper"></property>
        </bean>
    </beans>
    
    
    • mybatisPlus 适配 更改这里, 由原来的 SqlSessionFactoryBean改成MybatisSqlSessionFactoryBean
    <!--  配置SqlSessionFactoryBean
            Mybatis提供的: org.mybatis.spring.SqlSessionFactoryBean
            MP提供的:com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean
         -->
         
        <bean id="sqlSessionFactoryBean"
              class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
    

    3.通用增删改实现

    0.准备

    1.继承接口

    • 基于Mybatis: 在Mapper接口中编写CRUD相关的方法 提供Mapper接口所对应的SQL映射文件 以及 方法对应的SQL语句.

    • 基于MP: 让XxxMapper接口继承 BaseMapper接口即可.

    BaseMapper : 泛型指定的就是当前Mapper接口所操作的实体类类型

    public interface EmployeeMapper extends BaseMapper<Employee> { }
    

    2.BaseMapper 已经定义了各式各样的方法不用我们去定义

    1.insert方法

    1.指定主键策略

     @TableId:
    	 * 	 value: 指定表中的主键列的列名, 如果实体属性名与列名一致,可以省略不指定. 
    	 *   type: 指定主键策略. 
    
       @TableId(value="id" , type =IdType.AUTO)
    	private Integer id ;   //  int 
    

    2.指定表名注解

     * MybatisPlus会默认使用实体类的类名到数据中找对应的表. 
    
    @TableName(value="tbl_employee")
    public class Employee {
    

    3.test

    @Test
        public void testInsert() throws SQLException {
            //初始化Employee对象
            Employee employee  = new Employee();
            employee.setLastName("MP");
            employee.setEmail("mp@zhenqk.com");
            employee.setGender(1);
            employee.setAge(22);
            // employee.setSalary(20000.0);
            int a=employeeMapper.insert(employee);
        }
    

    4.再分析

    属性名是lastName ,而数据库是last_name(驼峰命名法) ,原因是因为全局默认配置是true

    5.如何配置 主键策略和表名

    • 通过全局配置整个都起作用,若通过注解只能在当前类有作用
    • 需要将配置作用在mybatis-session (注册)

    spring配置文件

    	<bean id="sqlSessionFactoryBean" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean">
    		<!-- 数据源 -->
    		<property name="dataSource" ref="dataSource"></property>
    		<property name="configLocation" value="classpath:mybatis-config.xml"></property>
    		<!-- 别名处理 -->
    		<property name="typeAliasesPackage" value="com.atguigu.mp.beans"></property>		
    // 		-------------------------------------------------
    		<!-- 注入全局MP策略配置 -->
    		<property name="globalConfig" ref="globalConfiguration"></property>
    	</bean>
    	
    	<!-- 定义MybatisPlus的全局策略配置-->
    	<bean id ="globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
    		<!-- 在2.3版本以后,dbColumnUnderline 默认值就是true  驼峰  -->
    		<property name="dbColumnUnderline" value="true"></property>
    		
    		<!-- 全局的主键策略  实体类中可以删除了 -->
    		<property name="idType" value="0"></property>
    		
    		<!-- 全局的表前缀策略配置 实体类中可以删除了 -->
    		<property name="tablePrefix" value="tbl_"></property>
    	</bean>
            
      // ------------   
    

    6.@TableField

    指定别名

    当数据库不存在此字段,选择性过滤插入 就是舍弃掉

    @TableField(exist=false)

    7.插入获取当前数据的主键值

    8.insertAllColumn方法 -- 全字段的插入,

    默认数据为空就不插入

    // insert方法在插入时, 会根据实体类的每个属性进行非空判断,只有非空的属性对应的字段才会出现到SQL语句中
    //insertAllColumn方法在插入时, 不管属性是否非空, 属性所对应的字段都会出现到SQL语句中. 
    

    2.更新操作

    1.updateById

    会做非空判断,选择性更新操作

    2.没有赋值就为null(在全赋值情况下) updateAllColumnById

    	//初始化修改对象
    		Employee employee = new Employee();
    		employee.setId(7);
    		employee.setLastName("小泽老师");
    		employee.setEmail("xz@sina.com");
    		employee.setGender(0);
    Integer result = employeeMapper.updateAllColumnById(employee);
    		
    System.out.println("result: " + result );
    

    没有给值就为ull,为每一个字段赋值

    3.通用的查询操作

    1.selectById(Serialize id)

    2.通过多列进行查询 id+lastName selectOne |

    注意: 最多只能查询一条,不能查询多条(当条件相同的列有多条的时候)

    3.通过多个id 进行查询 in () ===mybatis foreach

    4.通过map封装条件查询----selectByMap

    注意:是数据库类名

    1. 分页查询--selectPage

    wapper 条件构造器

    注意:当前页码,每页显示的条数,不是通过limit

    是一种内存分页 RowBound,物理分页借助分页插件

    • 不推荐使用

    4.通用删除

    1.根据id 进行删除--- deleteById

    2.根据条件进行删除-----deleteByMap

    where 进行可拼接

    3.批量删除 deleteBatchIds

    底层 in

    5.MP 启动自动注入SQL原理分析

      启动的时候就注入进来了,继承了BaseMapper 中提供的CRUB方法,方法来源于BaseMapper有方法就必须有SQL,因为Mabatis最终还是需要通过SQL语句操作实现,要熟悉:MyBatis 执行流程, 透过现象看本质

    Configuration 全局配置--->MappedStatement


     AutoSqlInjector

     SqlMethod 枚举对象 MP支持的SQL方法

     TableInfo 数据库表放射信息,可以获取数据库表的相关信息

     SqlSource :sql 处理对象

     MapperbuilderAssistant 用于缓存sql参数 查询方法的结果集处理等

    ​ 通过MapperbuilderAssistant 将每一个MappedStatement添加到Configuration中

     MappedStatements

    共17 种方法

    wrapper 实体对象封装操作类

    4.条件构造器

    1.EntityWrapper 简介

    • Mybatis-Plus 通过 EntityWrapper(简称 EW,MP 封装的一个查询条件构造器)或者Condition(与 EW 类似) 来让用户自由的构建查询条件,简单便捷,没有额外的负担,
      能够有效提高开发效率

    • 实体包装器,主要用于处理 sql 拼接,排序,实体参数查询等

    • 注意: 使用的是数据库字段,不是 Java 属性!

    • 条件参数的说明

    用的最多是查询操作

    2.需求

      现有一个需求,我们需要分页查询 tbl_employee 表中,年龄在 18~50 之间性别为男且姓名为 xx 的所有用户,这时候我们该如何实现上述需求呢?
      MyBatis : 需要在 SQL 映射文件中编写带条件查询的 SQL,并基于 PageHelper 插件完成分页. 实现以上一个简单的需求,往往需要我们做很多重复单调的工作。普通的 Mapper能够解决这类痛点吗?
      MP: 依旧不用编写 SQL 语句, MP 提供了功能强大的条件构造器 EntityWrapper

    利用条件构造器查询 		
    //我们需要分页查询tbl_employee表中,年龄在18~50之间且性别为男且姓名为Tom的所有用户
    		//  是数据库字段名
    		List<Employee> emps =employeeMapper.selectPage(new Page<Employee>(1, 2),
    				new EntityWrapper<Employee>()
    				.between("age", 18, 50)
    				.eq("gender", 1)
    				.eq("last_name", "Tom")
    			);
    	System.out.println(emps);
    

    3. 带条件的查询selectList方法

    小语法

    • or() 或者 关系 前面是一起的,后面是一起
    • orNew()
    	// 查询tbl_employee表中, 性别为女并且名字中带有"老师" 或者  邮箱中带有"a"
    		
    	List<Employee> emps = employeeMapper.selectList(
    			new EntityWrapper<Employee>()
    			.eq("gender", 0)
    				.like("last_name", "老师")
    				//.or()    
            // SQL: (gender = ? AND last_name LIKE ? OR email LIKE ?)    
    			.orNew()  
            // SQL: (gender = ? AND last_name LIKE ?) OR (email LIKE ?)   or New 另起一个括号
    			.like("email", "a")
    			);
    	System.out.println(emps);
    

    4. 带条件的修改

      update

    • 把tom 修改成苍老师
    
    		Employee employee = new Employee();
    		employee.setLastName("苍老师");
    		employee.setEmail("cls@sina.com");
    		employee.setGender(0);
    		
    		employeeMapper.update(employee, 
    					new EntityWrapper<Employee>()
    					.eq("last_name", "Tom")
    					.eq("age", 44)
    					);
    

    5.带条件的删除

    employeeMapper.delete(
    					new EntityWrapper<Employee>()
    					.eq("last_name", "Tom")
    					.eq("age", 22)
    				);
    

    6.其他常用方法

    orderby 默认是升序列

    orderSesc 降序

    		// 查询性别为女的, 根据age进行排序(asc/desc), 简单分页
    	List<Employee> emps  = employeeMapper.selectList(
    			new EntityWrapper<Employee>()
    			.eq("gender", 0)
    			.orderBy("age")
    			//.orderDesc(Arrays.asList(new String [] {"age"}))
    			.last("desc limit 1,3")
    		);
    

    last 具有SQL注入风险

    7.使用Condition的方式打开如上需求

    
    		List<Employee > emps = employeeMapper.selectPage(
    							new Page<Employee>(1,2), 
    							Condition.create()  // 获取方式一样 new EntityWrapper<Employee>() 
    							.between("age", 18, 50)
    							.eq("gender", "1")
    							.eq("last_name", "Tom")
    							
    							);
    		
    		System.out.println(emps);	
    
    • mp 条件构造器 Condition // EntityWrapper

    • 逆向工程qbc

    5.ActiveRecord 活动记录

    1.介绍

    ​ Active Record(活动记录),是一种领域模型模式,特点是一个模型类对应关系型数据库中的
    一个表,而模型类的一个实例对应表中的一行记录。
    ​ ActiveRecord 一直广受动态语言( PHP 、 Ruby 等)的喜爱,而 Java 作为准静态语言,
    对于 ActiveRecord 往往只能感叹其优雅,所以 MP 也在 AR 道路上进行了一定的探索

    概念慢慢理解 慢慢会用就可以了

    2.开启AR模式

    仅仅需要让实体类继承 Model 类且实现主键指定方法,即可开启 AR 之旅

    @TableName("tbl_employee")
    public class Employee extends Model<Employee>{
    // .. fields
    // .. getter and setter
    @Override
    protected Serializable pkVal() {
    return this.id;
    }
    

    3.基本CRUB

    1. 插入操作

    对象进行操作 自己插入自己

    /**
    	 * AR  插入操作
    	 */
    	@Test
    	public void  testARInsert() {
    		Employee employee = new Employee();
    		employee.setLastName("王老师");
    		employee.setEmail("king@ccut.com");
    		employee.setGender(1);
    		employee.setAge(35);
    		
    		boolean result = employee.insert();
    		System.out.println("result:" +result );
    	}
    

    2.修改操作

    
    	/**
    	 * AR 修改操作
    	 */
    	@Test
    	public void testARUpdate() {
    		Employee employee = new Employee();
    		employee.setId(20);
    		employee.setLastName("王大师");
    		employee.setEmail("king@ccut.com");
    		employee.setGender(1);
    		employee.setAge(36);
    		
    		
    		boolean result = employee.updateById();
    		System.out.println("result:" +result );
    		
    	}
    

    3.AR的查询操作

    1.selectById方法 and selectById(Serializable id)

    第一种方式:

    	Employee employee = new Employee();	
        Employee result = employee.selectById(14);
    	System.out.println(result );
    

    第二种方式:

    Employee employee = new Employee();
    		
    		employee.setId(14);
    	Employee result = employee.selectById();
    	System.out.println(result );
    

    2.selectAll()

    	Employee employee = new Employee();
    	List<Employee> emps = employee.selectAll();
      	System.out.println(emps);
    

    3.selectList and selectCount 方法

    		Employee employee = new Employee();
    		
    	List<Employee > emps= 
    				employee.selectList(new EntityWrapper<Employee>().like("last_name", "老师"));
    		System.out.println(emps);
    
    Employee employee = new Employee();
    Integer result = employee.selectCount(new EntityWrapper<Employee>().eq("gender", 0));
    // 全表统计 就不要加条件了 
    		System.out.println("result: " +result );
    

    4. 删除操作

    1.注意: 删除不存在的数据 逻辑上也是属于成功的.

    2.deleteById(id) 和deleteById()

    第一种方式

    Employee employee = new Employee();
    boolean result = employee.deleteById(2);
    

    第二种方式

    删除不存在在逻辑上也是成功的 
    Employee employee = new Employee();
    		employee.setId(2);
    		boolean result = employee.deleteById();
    	System.out.println("result:" +result );
    

    3.delete(wrapper)

    boolean result = employee.delete(new EntityWrapper<Employee>().like("last_name", "小"));
    		System.out.println(result );
    

    4.分页的复杂操作

    @Test
    	public void  testARPage() {
    		
    		Employee employee = new Employee();
    		
    		Page<Employee> page = employee.selectPage(new Page<>(1, 1), 
    				new EntityWrapper<Employee>().like("last_name", "老"));
    		List<Employee> emps = page.getRecords();  //获取查询数据库 查询回来的记录返回
    		System.out.println(emps);
    	}
    

    返回的是一个page 对象,更加的方便使用分页信息

    5.小结:

    1. AR 模式提供了一种更加便捷的方式实现 CRUD 操作,其本质还是调用的 Mybatis 对
      应的方法,类似于语法糖
      语法糖是指计算机语言中添加的某种语法,这种语法对原本语言的功能并没有影响.可以更方便开发者使用,可以避免出错的机会,让程序可读性更好.
    2. 到此,我们简单领略了 Mybatis-Plus 的魅力与高效率,值得注意的一点是:我们提供了强大的代码生成器,可以快速生成各类代码,真正的做到了即开即用

    6.代码生成器

    • 通过java代码来实现的

    • 逆向软件通过 xml而配置

    1.MP与MBG的简单比较

      1) MP 提供了大量的自定义设置,生成的代码完全能够满足各类型的需求
      2) MP 的代码生成器 和 Mybatis MBG 代码生成器:MP 的代码生成器都是基于 java 代码来生成。MBG 基于 xml 文件进行代码生成
     MyBatis 的代码生成器可生成: 实体类、Mapper 接口、Mapper 映射文件
     MP 的代码生成器可生成: 实体类(可以选择是否支持 AR)、Mapper 接口、Mapper 映射文件、 Service 层、Controller 层.
      3) 表及字段命名策略选择
      在 MP 中,我们建议数据库表名 和 表字段名采用驼峰命名方式, 如果采用下划线命名方式 请开启全局下划线开关,如果表名字段名命名方式不一致请注解指定,我们建议最好保持一致。
      这么做的原因是为了避免在对应实体类时产生的性能损耗,这样字段不用做映射就能直接和实体类对应。当然如果项目里不用考虑这点性能损耗,那么你采用下滑线也是没问题的,只需要在生成代码时配置 ; dbColumnUnderline 属性就可以

    2. 准备

    • 导入代码产生器依赖
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-generator</artifactId>
        <version>3.4.0</version>
    </dependency>
    
    <dependency>
        <groupId>org.apache.velocity</groupId>
        <artifactId>velocity-engine-core</artifactId>
        <version>2.2</version>
    </dependency>
    
    
    • 加入日志 sl4f 日志输出依赖
    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.7</version>
    </dependency>
    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.7</version>
    </dependency>
    

    3. GlobalConfig全局配置参数

    1.全局配置

    //1. 全局配置
    		GlobalConfig config = new GlobalConfig();
    		config.setActiveRecord(true) // 是否支持AR模式
    			  .setAuthor("weiyunhui") // 作者
    			  .setOutputDir("D:\workspace_mp\mp03\src\main\java") // 生成路径
    			  .setFileOverride(true)  // 文件覆盖
    			  .setIdType(IdType.AUTO) // 主键策略
    			  .setServiceName("%sService")  // 设置生成的service接口的名字的首字母是否为I
    			  					   // IEmployeeService
     			  .setBaseResultMap(true)
     			  .setBaseColumnList(true);
    

    2.数据源配置

    //2. 数据源配置
    		DataSourceConfig  dsConfig  = new DataSourceConfig();
    		dsConfig.setDbType(DbType.MYSQL)  // 设置数据库类型
    				.setDriverName("com.mysql.jdbc.Driver")
    				.setUrl("jdbc:mysql://localhost:3306/mp")
    				.setUsername("root")
    				.setPassword("1234");
    

    3.策略配置

    • 原来在配置文件
         	StrategyConfig stConfig = new StrategyConfig();
    		stConfig.setCapitalMode(true) //全局大写命名
    				.setDbColumnUnderline(true)  // 指定表名 字段名是否使用下划线
    				.setNaming(NamingStrategy.underline_to_camel) // 数据库表映射到实体的命名策略
    				.setTablePrefix("tbl_")
    				.setInclude("tbl_employee");  // 生成的表 所使用的表
    

    4.包名策略设置

    //4. 包名策略配置 
    		PackageConfig pkConfig = new PackageConfig();
    		pkConfig.setParent("com.atguigu.mp")
    				.setMapper("mapper")
    				.setService("service")
    				.setController("controller")
    				.setEntity("beans")
    				.setXml("mapper");
    
    //  .setBaseResultMap(true)    xml
     //			  .setBaseColumnList(true);
    

    5.整合配置

    //5. 整合配置
    		AutoGenerator  ag = new AutoGenerator();
    		
    		ag.setGlobalConfig(config)
    		  .setDataSource(dsConfig)
    		  .setStrategy(stConfig)
    		  .setPackageInfo(pkConfig);
    		
    		//6. 执行
    		ag.execute();
    

    导入包 spring-webmvc

    @Service
    public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService {
    	
    	//不用再进行mapper的注入.
    	
    	/**
    	 * EmployeeServiceImpl  继承了ServiceImpl
    	 * 1. 在ServiceImpl中已经完成Mapper对象的注入,直接在EmployeeServiceImpl中进行使用
    	 * 2. 在ServiceImpl中也帮我们提供了常用的CRUD方法, 基本的一些CRUD方法在Service中不需要我们自己定义.
    	 * 
    	 * 
    	 */
    }
    

    Controller

    @Controller
    @RequestMapping("/employee")
    public class EmployeeController {
    	
    	@Autowired
    	private EmployeeService employeeService; 
    	
    //	public String  login() {
    //		
    //		//employeeService.select
    //	}
    }
    
    

    更多详情信息可以看文档

    7.插件扩展

    1.介绍

      1) 插件机制: Mybatis 通过插件(Interceptor) 可以做到拦截四大对象相关方法的执行,根据需求,完 成相关数据的动态改变。 Executor StatementHandler ParameterHandler ResultSetHandler

       2) 插件原理 四大对象的每个对象在创建时,都会执行 interceptorChain.pluginAll(),会经过每个插 件对象的 plugin()方法,目的是为当前的四大对象创建代理。代理对象就可以拦截到四 大对象相关方法的执行,因为要执行四大对象的方法需要经过代理.

    2.分页插件

      物理分页

    com.baomidou.mybatisplus.plugins.PaginationInterceptor

      注册有两种方式

    1.mybaiss 配置文件

    <configuration>
    	<!-- <plugins>
    		<plugin interceptor="com.baomidou.mybatisplus.plugins.PaginationInterceptor"></plugin>
    	</plugins> -->
    
    </configuration>
    

     2.放在spring中 数组可以用list

    	<!-- 插件注册 -->
    		<property name="plugins">
    			<list>
    				<!-- 注册分页插件 -->
    				<bean class="com.baomidou.mybatisplus.plugins.PaginationInterceptor"></bean>
    		</list>
    			
    		</property>
    	</bean>
    

     测试方法

    	ApplicationContext ctx  = new ClassPathXmlApplicationContext("applicationContext.xml");
    	
    	EmployeeMapper employeeMapper = ctx.getBean("employeeMapper",EmployeeMapper.class);
    
    Page<Employee> page = new Page<>(1,1);
    		List<Employee > emps = 
    				employeeMapper.selectPage(page, null);
    		System.out.println(emps);
    

     把mapper 中开启二级缓存去掉

    • 注册分页插件后,Page对象的使用
    @Test
    	public void testPage() {
    		
    		Page<Employee> page = new Page<>(1,1);
    		
    		List<Employee > emps = 
    				employeeMapper.selectPage(page, null);
    		System.out.println(emps);
    		
    		
    		System.out.println("===============获取分页相关的一些信息======================");
    		
    		System.out.println("总条数:" +page.getTotal());
    		System.out.println("当前页码: "+  page.getCurrent());
    		System.out.println("总页码:" + page.getPages());
    		System.out.println("每页显示的条数:" + page.getSize());
    		System.out.println("是否有上一页: " + page.hasPrevious());
    		System.out.println("是否有下一页: " + page.hasNext());
    		
    		//将查询的结果封装到page对象中
    		page.setRecords(emps);
    		
    		
    	}
    

    3.执行分析插件(不建议生产环境用)

    1) com.baomidou.mybatisplus.plugins.SqlExplainInterceptor
    2) SQL 执行分析拦截器,只支持 MySQL5.6.3 以上版本
    3) 该插件的作用是分析 DELETE UPDATE 语句,防止小白
    或者恶意进行 DELETE UPDATE 全表操作
    4) 只建议在开发环境中使用,不建议在生产环境使用
    5) 在插件的底层 通过 SQL 语句分析命令:Explain 分析当前的 SQL 语句,
    根据结果集中的 Extra 列来断定当前是否全表操作。
    
    
    • 插件注册
    
    <!-- 插件注册 -->
    		<property name="plugins">
    			<list>
    				<!-- 注册分页插件 -->
    				<bean class="com.baomidou.mybatisplus.plugins.PaginationInterceptor"></bean>
    				
    				<!-- 注册执行分析插件   发现对全表的操作就停止  -->
    				<bean class="com.baomidou.mybatisplus.plugins.SqlExplainInterceptor">
    					<property name="stopProceed" value="true"></property>
    				</bean>
    
    • 测试
    /**
    	 * 测试SQL执行分析插件  发现全表删除操作 就停止
    	 */
    	@Test
    	public void testSQLExplain() {
    		
    		employeeMapper.delete(null);  // 全表删除
    	}
    

    explain sql分析

    4. 性能分析插件

     1) com.baomidou.mybatisplus.plugins.PerformanceInterceptor

     2) 性能分析拦截器,用于输出每条 SQL 语句及其执行时间

     3) SQL 性能执行分析,开发环境使用超过指定时间,停止运行。有助于发现问题----测试可以用

    • 注册插件
    	<!-- 注册性能分析插件 -->
    				<bean class="com.baomidou.mybatisplus.plugins.PerformanceInterceptor"> 是否格式化sql语句
    					<property name="format" value="true"></property>
    					<!-- <property name="maxTime" value="5"></property> -->   每条sql语句执行所消耗的时间
    				</bean>
    

    时间是 5毫秒

    • 测试
    /**
    	 * 测试 性能分析插件
    	 */
    	@Test
    	public void testPerformance() {
    		Employee employee = new Employee();
    		employee.setLastName("玛利亚老师");
    		employee.setEmail("mly@sina.com");
    		employee.setGender("0");
    		employee.setAge(22);
    		employeeMapper.insert(employee);
    	}
    


    5.乐观锁插件

     1) com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor

     2) 如果想实现如下需求: 当要更新一条记录的时候,希望这条记录没有被别人更新

     3) 乐观锁的实现原理: 取出记录时,获取当前 version 2 更新时,带上这个 version 2 执行更新时, set version = yourVersion+1 where version = yourVersion 如果 version 不对,就更新失败

     4) @Version 用于注解实体字段,必须要有。

    • domian
      • 加上字段

    ​ - 数据库也要加上 version int 11

    • 注册乐观锁
    	<!-- 基于注解的事务管理 -->
    	<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
    	
    	
    	<!--  配置SqlSessionFactoryBean 
    		Mybatis提供的: org.mybatis.spring.SqlSessionFactoryBean
    		MP提供的:com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean
    	 -->
    	<bean id="sqlSessionFactoryBean" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean">
    		<!-- 数据源 -->
    		<property name="dataSource" ref="dataSource"></property>
    		<property name="configLocation" value="classpath:mybatis-config.xml"></property>
    		<!-- 别名处理 -->
    		<property name="typeAliasesPackage" value="com.atguigu.mp.beans"></property>		
    		
     		<!-- 注入全局MP策略配置 -->
    		<property name="globalConfig" ref="globalConfiguration"></property>
    		
    		<!-- 插件注册 -->
    		<property name="plugins">
    			<list>
    				<!-- 注册分页插件 -->
    				<bean class="com.baomidou.mybatisplus.plugins.PaginationInterceptor"></bean>
    				
    				<!-- 注册执行分析插件 -->
    				<bean class="com.baomidou.mybatisplus.plugins.SqlExplainInterceptor">
    					<property name="stopProceed" value="true"></property>
    				</bean>
    				
    				<!-- 注册性能分析插件 -->
    				<bean class="com.baomidou.mybatisplus.plugins.PerformanceInterceptor">
    					<property name="format" value="true"></property>
    					<!-- <property name="maxTime" value="5"></property> -->
    				</bean>
    				
    				<!-- 注册乐观锁插件 -->
    				<bean class="com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor">
    				</bean>
    			
    			</list>
    			
    		</property>
    		
    	</bean>
    

     测试比对

    	/**
    	 * 测试 乐观锁插件
    	 */
    	
    	@Test
    	public void testOptimisticLocker() {
    		//更新操作
    		Employee employee = new Employee();
    		employee.setId(15);
    		employee.setLastName("TomAA");
    		employee.setEmail("tomAA@sina.com");
    		employee.setGender("1");
    		employee.setAge(22);
    		employee.setVersion(3);
    		
    		employeeMapper.updateById(employee);
    		
    	}
    

    8.全局配置

    ​ 根据 MybatisPlus 的 AutoSqlInjector 可以自定义各种你想要的 sql ,注入到全局中,相当于自 定义 Mybatisplus 自动注入的方法。

    之前需要在 xml 中进行配置的 SQL 语句,现在通过扩展 AutoSqlInjector 在加载 mybatis 环境 时就注入。

    8.1 AutoSqlInjector

    1. 在 Mapper 接口中定义相关的 CRUD 方法

    1. 扩展 AutoSqlInjector inject 方法,实现 Mapper 接口中方法要注入的 SQL

    新建包 injector/MySqlInjector.java

    /**
     * 自定义全局操作
     */
    public class MySqlInjector  extends AutoSqlInjector{
    	
    	/**
    	 * 扩展inject 方法,完成自定义全局操作
    	 a模仿 injectDeleteSql
    	 */
    	@Override
    	public void inject(Configuration configuration, MapperBuilderAssistant builderAssistant, Class<?> mapperClass,
    			Class<?> modelClass, TableInfo table) {
    		//将EmployeeMapper中定义的deleteAll, 处理成对应的MappedStatement对象,加入到configuration对象中。
    		
    		//注入的SQL语句
    		String sql = "delete from " +table.getTableName();
    		//注入的方法名   一定要与EmployeeMapper接口中的方法名一致
    		String method = "deleteAll" ;
    		
    		//构造SqlSource对象
    		SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
    		
    		//构造一个删除的MappedStatement
    		this.addDeleteMappedStatement(mapperClass, method, sqlSource);
    		
    	}
    }
    

     3) 在 MP 全局策略中,配置 自定义注入器

    <!-- 定义MybatisPlus的全局策略配置-->
    	<bean id ="globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
    		<!-- 在2.3版本以后,dbColumnUnderline 默认值就是true -->
    		<property name="dbColumnUnderline" value="true"></property>
    		
    		<!-- Mysql 全局的主键策略 -->
    		<!-- <property name="idType" value="0"></property> -->
    		
    		<!-- Oracle全局主键策略 -->
    		<property name="idType" value="1"></property>
    		
    		<!-- 全局的表前缀策略配置 -->
    		<property name="tablePrefix" value="tbl_"></property>
    		
    		<!--注入自定义全局操作 
    		<property name="sqlInjector" ref="mySqlInjector"></property>
    		
    		
         	<property name="keyGenerator" ref="oracleKeyGenerator"></property>
    	</bean>
    	
    	<!-- 定义自定义注入器 -->
    	<bean id="mySqlInjector" class="com.ccut.mp.injector.MySqlInjector"></bean>
    	
        
        
    

    测试

    	/**
    	 * 测试自定义全局操作
    	 */
    	@Test
    	public void  testMySqlInjector() {
    		Integer result = employeeMapper.deleteAll();
    		System.out.println("result: " +result );
    	}
    

    没有写映射文件mapper 是在启动的时候就注入了

    8.2 自定义注入器的应用之 逻辑删除

    假删除、逻辑删除: 并不会真正的从数据库中将数据删除掉,而是将当前被删除的这条数据 中的一个逻辑删除字段置为删除状态. tbl_user logic_flag = 1 → -1

    1. com.baomidou.mybatisplus.mapper.LogicSqlInjector

    2. logicDeleteValue 逻辑删除全局值

    3. logicNotDeleteValue 逻辑未删除全局值

    4. 在 POJO 的逻辑删除字段 添加 @TableLogic 注解

    5. 会在 mp 自带查询和更新方法的 sql 后面,追加『逻辑删除字段』=『LogicNotDeleteValue 默认值』 删除方法: deleteById()和其他 delete 方法, 底层 SQL 调用的是 update tbl_xxx set 『逻辑删除字段』=『logicDeleteValue 默认值』

    8.3 实战

    全局sql 注入器的使用,配置

    1.appcattionContex.xml

    
    <!-- 定义MybatisPlus的全局策略配置-->
    	<bean id ="globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
    		<!-- 在2.3版本以后,dbColumnUnderline 默认值就是true -->
    		<property name="dbColumnUnderline" value="true"></property>
    		.....
    	 	
    	 	
    	 	<!-- 注入逻辑删除 -->
    	 	<property name="sqlInjector" ref="logicSqlInjector"></property>
    	 	
    	 	<!-- 注入逻辑删除全局值 -->
    	 	<property name="logicDeleteValue" value = "-1"></property>
    	 	<property name="logicNotDeleteValue" value="1"></property>
    	 	
    	 	
    	</bean>
    	
    	
    	<!-- 逻辑删除 -->
    	<bean id="logicSqlInjector" class="com.baomidou.mybatisplus.mapper.LogicSqlInjector"></bean>
    	
    

    创建表:

    logflag 字段

    实体类

    usermapper

    直接继承BaseMapper<User>
    
    /**
    	 * 测试逻辑删除
    	 */
    	@Test
    	public void testLogicDelete() {
    		
    //		Integer result = userMapper.deleteById(1); 变成了更新状态 
    //		System.out.println("result:" +result );
    		
    		User user = userMapper.selectById(1);  //查询不到的 null   判断 and  逻辑字段等于1
    		System.out.println(user);
    	}
    

    9.公共字段填充

    希望有些默认的值给他填充上去

     9.1 元数据处理器接口 com.baomidou.mybatisplus.mapper.MetaObjectHandler

    insertFill(MetaObject metaObject) 插入的填充

    updateFill(MetaObject metaObject) 更新的时候填充

    metaobject: 元对象. 是 Mybatis 提供的一个用于更加方便,更加优雅的访问对象的属性, 给对象的属性设置值 的一个对象. 还会用于包装对象. 支持对 Object 、Map、Collection 等对象进行包装

    本质上 metaObject 获取对象的属性值或者是给对象的属性设置值,最终是要 通过 Reflector 获取到属性的对应方法的 Invoker, 最终 invoke.

     9.2 开发步骤

    1. 注解填充字段 @TableFile(fill = FieldFill.INSERT) 查看 FieldFill

    2. 自定义公共字段填充处理器

    3. MP 全局注入 自定义公共字段填充处理器

    1.实现步骤

    • 实体类

    • 公共字段处理器

    • 全局配置

    放在全局策略上

    	<!-- 注入公共字段填充处理器 -->
    	 	<property name="metaObjectHandler" ref="myMetaObjectHandler"></property>
    	 	
    	 	<!-- 注入Oracle主键Sequence -->
    	 	<property name="keyGenerator" ref="oracleKeyGenerator"></property>
    	</bean>
    	
    	
    	
    <!-- 公共字段填充 处理器 -->
    	<bean id="myMetaObjectHandler" class="com.atguigu.mp.metaObjectHandler.MyMetaObjectHandler"> </bean>	
    	
    	
    

    2.自定义填充处理器的实现

    /**
     * 自定义公共字段填充处理器
     */
    public class MyMetaObjectHandler extends MetaObjectHandler {
    	
    	/**
    	 * 插入操作 自动填充
    	 */
    	@Override
    	public void insertFill(MetaObject metaObject) {
    		//获取到需要被填充的字段的值
    		Object fieldValue = getFieldValByName("name", metaObject);
    		if(fieldValue == null) {
    			System.out.println("*******插入操作 满足填充条件*********");
    			setFieldValByName("name", "weiyunhui", metaObject);
    		}
    		
    	}
    	/**
    	 * 修改操作 自动填充
    	 */
    	@Override
    	public void updateFill(MetaObject metaObject) {
    		Object fieldValue = getFieldValByName("name", metaObject);
    		if(fieldValue == null) {
    			System.out.println("*******修改操作 满足填充条件*********");
    			setFieldValByName("name", "weiyh", metaObject);
    		}
    	}
    
    }
    

    3.测试

    /**
    	 * 测试公共字段填充
    	 有名字就不会进行填充
    	 */
    	@Test
    	public void testMetaObjectHandler() {
    		User user = new User();
    		//user.setName("Tom");
    		 // userMapper.insert(user);
    		user.setId(5);
    		user.setLogicFlag(1);
    		
    		userMapper.updateById(user);
    	}
    

    对某个字段修改,就不适合了,它认为没有值就填充了

    10. Oracle 主键 Sequence

    MySQL: 支持主键自增。 IdType.Auto
    Oracle: 序列(Sequence)  不支持主键自增
    

    1.步骤

    1. 实体类配置主键 Sequence @KeySequence(value=”序列名”,

    clazz=xxx.class 主键属性类 型)

    1. 全局 MP 主键生成策略为 IdType.INPUT

    多个 ,也就是整个环境都在使用oracle数据库

     <!-- Oracle全局主键策略 -->
    		<property name="idType" value="1"></property>
    
    1. 全局 MP 中配置 Oracle 主键 Sequence com.baomidou.mybatisplus.incrementer.OracleKeyGenerator
     <!-- 注入Oracle主键Sequence -->
    	 	<property name="keyGenerator" ref="oracleKeyGenerator"></property>
    	</bean>
    	
    	
    
    <!-- 配置Oracle主键Sequence -->
    	<bean id="oracleKeyGenerator" class="com.baomidou.mybatisplus.incrementer.OracleKeyGenerator"></bean>
    		
    
    1. 可以将@keySequence 定义在父类中,可实现多个子类对应的多个表公用一个 Sequence

    2.Oracle 驱动依赖问题


    3.配置连接信息

    orcl.driver=oracle.jdbc.OracleDriver
    orcl.url=jdbc:oracle:thin:@localhost:1521:xe
    orcl.username=system
    orcl.password=1234
    
    

    4.创建表及序列


    5.演示.

    	/**
    	 * 测试Oracle 主键 Sequence
    	 */
    	@Test
    	public void testOracle() {
    		User user = new User();
    		user.setLogicFlag(1);
    		user.setName("OracleSEQ");
    		userMapper.insert(user);
    	}
    

    6. 扩展 多个实体类公用一个序列

    11. idea

    MybatisX 辅助 idea 快速开发插件,
    为效率而生. 可以实现 java 与 xml 跳转,根据 Mapper 接口中的方法自动生成 xml 结构.
    官方安装: File -> Settings -> Plugins -> Browse Repositories.. 输入 mybatisx 安装下载
    Jar 安装: File -> Settings -> Plugins -> Install plugin from disk.. 选中 mybatisx..jar 安装

    不停的思考,就会不停的进步
  • 相关阅读:
    使用Apache Commons-email邮件客户端发邮件
    Jfinal开发代码碎片_导出报表_配置druid数据源_使用guava_获取当前操作系统_JDK版本_jfinal-utils_jfinal验证码
    Memcached缓存集群_创建多实例
    HttpClient取得自定义的状态码302,并获取Header中的参数Location
    对象序列化和反序列化
    【校园电子书城】测试及部署
    mysql导入txt文件
    【校园电子书城】部分代码及数据库设计
    【校园电子书城】需求分析
    Domain logic approaches
  • 原文地址:https://www.cnblogs.com/zhenqk/p/13737257.html
Copyright © 2011-2022 走看看