通用Mapper

通用 Mapper 笔记

1. 引入

Tip 💡

通用 mapper,只支持单表操作

1.1 作用:

替我们生成常用增删改查操作的 sql语句。

1.2 代码官方发布地址

1.3 前置知识

  • spring
  • mybatis

2. 快速入门

  • 创建一个 maven工程

2.0 pom.xml

    <dependencies>
        <!-- https://mvnrepository.com/artifact/tk.mybatis/mapper -->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper</artifactId>
            <version>4.1.5</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.6</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.32</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.25</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.6</version>
        </dependency>
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.8</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.43</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.3.8</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>5.3.8</version>
        </dependency>
    </dependencies>

2.1 创建测试数据

CREATE TABLE `tabple_emp` (
`emp_id` int NOT NULL AUTO_INCREMENT ,
`emp_name` varchar(500) NULL ,
`emp_salary` double(15,5) NULL ,
`emp_age` int NULL ,
PRIMARY KEY (`emp_id`)
);
INSERT INTO `tabple_emp` (`emp_name`, `emp_salary`, `emp_age`) VALUES ('tom', '1254.37', '27');
INSERT INTO `tabple_emp` (`emp_name`, `emp_salary`, `emp_age`) VALUES ('jerry', '6635.42', '38');
INSERT INTO `tabple_emp` (`emp_name`, `emp_salary`, `emp_age`) VALUES ('bob', '5560.11', '40');
INSERT INTO `tabple_emp` (`emp_name`, `emp_salary`, `emp_age`) VALUES ('kate', '2209.11', '22');
INSERT INTO `tabple_emp` (`emp_name`, `emp_salary`, `emp_age`) VALUES ('justin', '4203.15', '30');

2.2 Java 实体类

  • 考虑到基本数据类型在 Java类中都有默认值,会导致 mybatis在执行相关操作时很难判断当前字段是否为 null。所以在 mybatis环境下使用 Java实体类时尽量不要使用基本类型,要是用包装类型。

  • 建议实现 序列化接口。

    public class Employee implements Serializable {
        private Integer empId;
        private String empName;
        private Double empSalary;
        private Integer empAge;
    }
    

2.3 spring 配置

mybatis-conf.xml没有写任何

#jdbc.properties
jdbc.user=root
jdbc.password=root
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.driver=com.mysql.jdbc.Driver
<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!--配置数据源-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="driverClass" value="${jdbc.driver}"/>
    </bean>
    <!--整合 mybatis-->
    <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--扫描 mapper接口所在的包-->
    <!--整合 通用 mapper所需要做的配置修改-->
    <!--原始全类名:rog.mybatis.spring.mapper.MapperScannerConfigurer-->
    <!--通用 mapper使用:tk.mybatis.spring.mapper.MapperScannerConfigurer-->
    <bean class="tk.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.cainiao.mapper"/>
    </bean>
    <!--配置 service自动扫描的包-->
    <context:component-scan base-package="com.cainiao.services"/>
    <!--配置声明事务-->
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
</beans>

2.4 其他

//dao 层
/**
 * @author zhaokuii11@163.com
 * @create 2021-11-05 20:15
 * @Description 具体操作数据库的 mapper接口,
 * 需要继承 mapper提供的核心接口,:Mapper<T>
 * 泛型类型就是实体类的类型
 */
public interface EmployeeMapper extends Mapper<Employee> {}
//service 层
@Service
public class EmployeeService {
    @Autowired
    private EmployeeMapper employeeMapper;
    public Employee getOne(Employee employee) {
        return employeeMapper.selectOne(employee);
    }
}

2.5 测试

public class EmployeeMapperTest {
    private ClassPathXmlApplicationContext application
            = new ClassPathXmlApplicationContext("application.xml");
    private EmployeeService employeeService = application.getBean(EmployeeService.class);

    @Test
    public void testDeleteByPrimaryKey() {
        //1. 创建封装查询条件的实体类对象
        Employee employee = new Employee(null, "bob", null, null);
        //2 执行该方法
        Employee employee1 = employeeService.getOne(employee);
        //3. 打印输出
        System.out.println(employee1);
    }
}

注意事项

  • 默认查询的是根实体类类名小写的表,如果不同在实体类的里面使用 @Table注解标注表名
  • 扫描 mapper接口所在的包,使用的 tk.mybatis.jar 包下的

3. 常用注解

@Table

  • 作用:建立实体类和数据库表之间的对应关系。

    默认规则:实体类名首字母小写作为表名。Employee ==》employee

  • 用法:在 @Table 注解的 name属性中指定目标数据库表的表名

@Column 注解

  • 作用:建立实体类字段和数据库表字段之间的对应关系。

  • 默认规则:实体类字段:驼峰式命名。数据库表字段:使用 “_”区分各个单词

  • 用法:在 @Colun注解的 name属性中指定目标字段的字段名

@Id 注解

  • 通用 Mapper在执行 xxxByPrimaryKey(Key) 方法时,有两种情况。
    1. 没有使用 @Id注解明确指定主键字段。

      ==>  Preparing: SELECT emp_id,emp_name,emp_salary,emp_age FROM tabple_emp WHERE emp_id = ? AND emp_name = ? AND emp_salary = ? AND emp_age = ?
      ==> Parameters: 3(Integer), 3(Integer), 3(Integer), 3(Integer)
      

      之所以会生成生面这样的 where子句是因为通用 mapper将实体类中的所有字段拿来放在一起作为联合主键。

    2. 使用 @Id主键明确标记和数据库表中主键字段对应的实体类字段。

@GeneratedValue 注解

  • 作用:让通用 mapper在执行 insert操作之后将数据库自动生成的主键会写到实体类对象中。

    • 自增主键用法

    • 序列主键用法

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY.generator="select SEQ_ID.netxval from dual")
    private Integer id;

    
    - 应用场景:购物车结账
    
    增加商品销量
    
    减少商品库存
    
    生成订单数据-》封装到 Order对象中-》保存 Order对象-》数据库自动生成主键值-》会写到实体类对象 Order中
    
    生成一系列订单详情数据=》list\<OrderItem>=>在每一个 OrderItem中设置Order对象的主键值作为外键=》批量保存 list\<OrderItem>
    
    

@Transient 主键

  • 用于标记不与数据库表字段对应的实体类字段。

4. 常用方法

BaseSelectMapper

@RegisterMapper
public interface BaseSelectMapper<T> extends 
    SelectOneMapper<T>, //T selectOne(T var1);
	SelectMapper<T>, //List<T> select(T var1);
	SelectAllMapper<T>, //List<T> selectAll();
	SelectCountMapper<T>, //int selectCount(T var1); 
	SelectByPrimaryKeyMapper<T>, //T selectByPrimaryKey(Object var1); 
	ExistsWithPrimaryKeyMapper<T> //boolean existsWithPrimaryKey(Object var1); 
    {}

SelectOne

  • 通用 mapper替我们自动生成的 sql语句情况。

    • 实体类封装查询条件生成 where子句的规则。

      使用非空的值生成 where子句

      在条件表达式中使用 “=”进行比较

    • 要求必须返回一个实体类结果,如果有多个,则会抛出异常。

xxxByPrimaryKey 方法

  • 需要使用 @Id 主键明确标记和数据库主键字段对应的实体类字段,否则通用 Maper会见所有实体类字段作为联合主键。

xxxSelect 方法

  • 非主键字段如果 为 null值,则不加到 sql语句中。

5. QBC 查询

5.1 概念

  • query by criteria

    criteria 是 criterion的复数形式。意思是:规则,标准,准则。在 sql语句中相当于查询条件。

    qbc 查询是将查询条件通过 java对象进行模块化封装。

5.1 示例代码

    @Test
    public void testSelectByExample() {
        //目标: where (emp_salary>? and emp_age<? ) or (emp_salary<? and emp_age>?)
        //1. 创建 Example对象
        Example example = new Example(Employee.class);
        //==================================
        //i 设置排序信息
        example.orderBy("empSalary").asc().orderBy("empAge").desc();
        //ii 设置 去重
        example.setDistinct(true);
        //iii 设置 select字段
        example.selectProperties("empName", "empSalary");
        //==================================
        //2. 通过 Example对象创建 Criteria 对象
        Example.Criteria criteria1 = example.createCriteria();
        Example.Criteria criteria2 = example.createCriteria();
        //3. 在两个 Criteria 对象中分别设置查询条件
        //        property参数:实体类的属性名
        //        value参数:实体类的属性值
        criteria1.andGreaterThan("empSalary", "3000")
                .andLessThan("empAge", 25);
        criteria2.andLessThan("empSalary", 5000)
                .andGreaterThan("empAge", 30);
        //4. 使用 or关键词组组装两个 Criteria对象
        example.or(criteria2);
        //5. 执行查询
        List<Employee> empList = employeeService.SelectByExample(example);
        System.out.println(empList);
        // SELECT emp_id,emp_name,emp_salary,emp_age FROM tabple_emp WHERE 
        //  ( ( emp_salary > ? and emp_age < ? ) or ( emp_salary < ? and emp_age > ? ) )
        // 3000(String), 25(Integer), 5000(Integer), 30(Integer)

        // SELECT distinct emp_name , emp_salary FROM tabple_emp WHERE
        //  ( ( emp_salary > ? and emp_age < ? ) or ( emp_salary < ? and emp_age > ? ) )
        //  order by emp_salary ASC,emp_age DESC
    }

    public List<Employee> SelectByExample(Example example) {
        return employeeMapper.selectByExample(example);
    }

6. 逆向工程

6.1 原生 mybatis 逆向工程和通用 mapper逆向工程对比。

6.1.1 pom.xml

<!--属性配置-->
	<properties>
        <!--  MyBatis Generator  -->
        <!--Java接口和实体类  -->
        <!--targetJavaProject:声明存放源码的目录位置 ${basedir}应用工程根目录-->
        <targetJavaProject>${basedir}/src/main/java</targetJavaProject>
        <!--targetMapperPackage:声明 mbg生成 XxxMapper接口后存放的package位置-->
        <targetMapperPackage>com.cainiao.shop.mappers</targetMapperPackage>
        <!--targetModelPackage:声明mgb生成 实体类后存放的 package位置-->
        <targetModelPackage>com.cainiao.shop.entities</targetModelPackage>
        <!-- targetResourcesProject:声明存放资源文件的目录位置和 XML位置  -->
        <targetResourcesProject>${basedir}/src/main/resources</targetResourcesProject>
        <!--targetXMLPackage:声明存放具体 XxxMapper.xml文件的目录位置-->
        <targetXMLPackage>mappers</targetXMLPackage>
        <!--  通用 mapper版本号  -->
        <mapper.version>4.1.5</mapper.version>
        <!--mysql 驱动版本号-->
        <mysql.version>5.1.43</mysql.version>
    </properties>

<!--逆向工程依赖的 jar包-->
    <dependencies>
        <!--mybatis 的逆向工程-->
        <!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core -->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.5</version>
        </dependency>
        <!-- 如果你只需要用到通用 Mapper 中的插件,可以只引入 mapper-generator -->
        <!-- 注意,这个包不需要和上面的 mapper 同时引入,mapper 中包含 generator -->
        <!-- https://mvnrepository.com/artifact/tk.mybatis/mapper-generator -->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-generator</artifactId>
            <version>1.1.4</version>
        </dependency>
        <!-- 通用 Mapper -->
        <!-- https://mvnrepository.com/artifact/tk.mybatis/mapper -->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper</artifactId>
            <version>4.1.5</version>
        </dependency>
    </dependencies>

<!--插件配置 和 mgb的 generatorConfig.xml 文件的位置-->
    <build>
        <plugins>
            <plugin>
                <!--mgb 工程的依赖-->
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.2</version>
                <!--配置 mgb的 generatorConfig.xml 文件的位置-->
                <configuration>
                    <configurationFile>${basedir}/target/classes/generatorConfig.xml</configurationFile>
                    <overwrite>true</overwrite>
                    <verbose>true</verbose>
                </configuration>
                <!--插件的依赖信息-->
                <dependencies>
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>${mysql.version}</version>
                    </dependency>
                    <dependency>
                        <groupId>tk.mybatis</groupId>
                        <artifactId>mapper</artifactId>
                        <version>${mapper.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>

Tip 💡

如果:generatorConfig.xml 找不到。

maven 重新清理一下重新打包。

或者修改为 resource下。【因为我本来在是写在 resource下,找不到就改了】

6.1.2 generator.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <!--引入外部配置文件-->
    <properties resource="jdbc.properties"/>

    <context id="Mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat">
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>
        <!--配置通用 mapper的 mgb插件的相关信息-->
        <!--mapper.plugin=tk.mybatis.mapper.generator.MapperPlugin 这一项的引用-->
        <plugin type="${mapper.plugin}">
            <!--这个也是 jdbc外部的引用-->
            <property name="mappers" value="${mapper.Mapper}"/>
        </plugin>
        <!--配置连接数据库的相关信息-->
        <jdbcConnection driverClass="${jdbc.driverClass}"
                        connectionURL="${jdbc.url}"
                        userId="${jdbc.user}"
                        password="${jdbc.password}">
        </jdbcConnection>
        <!--配置Java实体类村方法的位置  pom.xml 文件的内容-->
        <javaModelGenerator
                targetPackage="${targetModelPackage}"
                targetProject="${targetJavaProject}"/>
        <!--配置 存放 XxxMapper.xml 存方的位置-->
        <sqlMapGenerator
                targetPackage="${targetXMLPackage}"
                targetProject="${targetResourcesProject}"/>
        <!--配置 存放 XxxMapper.java 存方的位置-->
        <javaClientGenerator
                targetPackage="${targetMapperPackage}"
                targetProject="${targetJavaProject}"
                type="XMLMAPPER"/>
        <!--根据数据库表生成 java文件的相关规则
            tableName = "%" 表示数据库表中所有的表都参与逆向工程,此时使用默认规则
            默认规则:table_dept ==> tableDept
            不符合默认规则时,需要使用 domainObjectName 和 tableName两个属性明确指定
        -->
        <table tableName="tabple_emp" domainObjectName="Employee">
            <!--配置组件生成策略-->
            <generatedKey column="emp_id" sqlStatement="Mysql" identity="true"/>
        </table>
    </context>
</generatorConfiguration>

6.1.3 jdbc.properties

# 数据库配置
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.user=root
jdbc.password=root
#c3p0
jdbc.maxPoolSize=50
jdbc.minPoolSize=10
jdbc.maxStatements=100
jdbc.testConnection=true
# 通用Mapper配置
mapper.plugin=tk.mybatis.mapper.generator.MapperPlugin
# Mapper 可以不用指定 可以改【上面这个的就不能该了】
mapper.Mapper=tk.mybatis.mapper.common.Mapper

6.1.4 运行插件

6.2 参考文档地址

7. 自定义 Mapper<T> 接口

7.1 用途

  • 让我们可以根据开发的实际需要对 Mapper<T> 接口进行定制。

7.2 创建自定义 Mapper<T> 接口

public interface EmployeeMapper extends MyMapper<Employee> {
}
public interface MyMapper<T> extends SelectAllMapper<T>, SelectByExampleMapper<T> {
  //继承这里我们自由选择
}

Tip💡

自定义的 Maper不能和 实体类的 Mapper放在同一个目录

7.3 配置 MapperScannerConfigurer 注册 MyMapper<T>

  • 默认配置的是 通用Mapper的,这里我们的值替代它的。
    <!--扫描 mapper接口所在的包-->
    <!--整合 通用 mapper所需要做的配置修改-->
    <!--原始全类名:rog.mybatis.spring.mapper.MapperScannerConfigurer-->
    <!--通用 mapper使用:tk.mybatis.spring.mapper.MapperScannerConfigurer-->
    <bean class="tk.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.cainiao.mapper.mappers"/>
        <property name="properties">
            <value>mapers=com.cainiao.mapper.myconfig.MyMapper</value>
        </property>
    </bean>
posted @ 2021-11-10 10:39  MikiKawai  阅读(32)  评论(0编辑  收藏  举报