通用Mapper
通用 Mapper 笔记
1. 引入
Tip 💡
通用 mapper,只支持单表操作
1.1 作用:
替我们生成常用增删改查操作的 sql语句。
1.2 代码官方发布地址
- 作者地址:https://gitee.com/free
- 项目地址:https://gitee.com/free/Mapper
- wiki:https://gitee.com/free/Mapper/wikis/Home
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) 方法时,有两种情况。
-
没有使用 @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将实体类中的所有字段拿来放在一起作为联合主键。
-
使用 @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 参考文档地址
- github https://mapperhelper.github.io/docs/3.usembg/
- github https://github.com/abel533/Mapper/wiki/4.1.mappergenerator
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>