1 Spring整合MyBatisPlus
1.1 Spring整合MyBatisPlus
01.SpringBoot整合MyBatisPlus
a.Maven
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>最新版本</version>
</dependency>
b.Gradle
//Gradle Version:<4.1
compile group: 'com.baomidou', name: 'mybatis-plus-boot-starter', version: '最新版本'
//Gradle Version:>=4.1 (The function compile has been deprecated since Gradle 4.10, and removed since Gradle 7.0. Please use implementation instead.)
implementation 'com.baomidou:mybatis-plus-boot-starter:最新版本'
02.Spring整合MyBatisPlus
a.Maven
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>最新版本</version>
</dependency>
b.Gradle
//Gradle Version:<4.1
compile group: 'com.baomidou', name: 'mybatis-plus', version: '最新版本'
//Gradle Version:>=4.1 (The function compile has been deprecated since Gradle 4.10, and removed since Gradle 7.0. Please use implementation instead.)
implementation 'com.baomidou:mybatis-plus:最新版本'
03.配置文件如下:
a.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"
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 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<!--数据源c3p0 -->
<context:property-placeholder location="classpath:db.properties" />
<!--数据源存在位置:db.properties-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--事务管理器-->
<bean id="dataSourceTransactionManger" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--数据源-->
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="dataSourceTransactionManger" />
<!--MyBatis: SqlSessionFactoryBean-->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--数据源-->
<property name="dataSource" ref="dataSource"/>
<!--mybatis.xml-->
<property name="configLocation" value="classpath:mybatis.xml"/>
<!--别名-->
<property name="typeAliasesPackage" value="org.myslayers.entity"/>
</bean>
<!--MyBatis:只写接口,不写实现类-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--MyBatis会自动将接口实现-->
<property name="basePackage" value="org.myslayers.mapper"/>
</bean>
</beans>
b.db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mp
jdbc.username=root
jdbc.password=4023615
c.mybatis.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>
<!--配置日志 LOG4J日志默认的配置文件是 log4j.properties-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="logImpl" value="LOG4J"/>
</settings>
</configuration>
d.log4j.properties
log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
e.pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.myslayers</groupId>
<artifactId>MyBatisPlus</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--mybatis-plus: ①MyBatisPLus、②MyBatis、③MyBatis-spring整合jar包-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.1.1</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
<!--日志-->
<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>
<!--spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.24.RELEASE</version>
</dependency>
<!--ORM-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.3.24.RELEASE</version>
</dependency>
</dependencies>
</project>
04.测试
public class Test {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//ComboPooledDataSource
ComboPooledDataSource ds = (ComboPooledDataSource)context.getBean("dataSource");
System.out.println("数据源:" + ds);
Connection connection = ds.getConnection();
System.out.println("连接对象" + connection);
}
}
加载文件顺序:
applicationContext.xml
-> db.properties
-> property-placeholder
-> 数据源dataSource
-> sqlSessionFactoryBean
-> mybatis.xml
-> StudentMapper.getXxx()
-> 操作DB
1.2 MyBatisPlus快速测试
01.添加测试依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter-test</artifactId>
<version>3.5.3.1</version>
</dependency>
02.编写测试用例
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import static org.assertj.core.api.Assertions.assertThat;
@MybatisPlusTest
class MybatisPlusSampleTest {
@Autowired
private SampleMapper sampleMapper;
@Test
void testInsert() {
Sample sample = new Sample();
sampleMapper.insert(sample);
assertThat(sample.getId()).isNotNull();
}
}
1.3 MyBatisPlus底层原理
00.原理
MyBatis/MyBatis-Plus都是通过"MappedStatement对象"来指向"增刪改"
预加载:MP启动时,会指定加载所有常见的CRUD语句(来自于MP提供的BaseMapperf接口),并将这些语句封装到了MappedStatement对象中。
1.4 MyBatis与MyBatisPlus切换
00.MyBatis与MyBatisPlus切换?只需更改此处即可
a.MyBatis
<!--MyBatis: SqlSessionFactoryBean-->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--数据源-->
<property name="dataSource" ref="dataSource"/>
<!--mybatis.xml-->
<property name="configLocation" value="classpath:mybatis.xml"/>
<!--别名-->
<property name="typeAliasesPackage" value="org.myslayers.entity"/>
</bean>
b.MyBatisPlus
<!--MyBatis: SqlSessionFactoryBean-->
<bean id="sqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<!--数据源-->
<property name="dataSource" ref="dataSource"/>
<!--mybatis.xml-->
<property name="configLocation" value="classpath:mybatis.xml"/>
<!--别名-->
<property name="typeAliasesPackage" value="org.myslayers.entity"/>
</bean>
2 MyBatis注解、MyBatisPlus注解、Lombok注解
2.1 附:MyBatis注解
00.注解汇总
@Arg
@AutomapConstructor
@CacheNamespace
@CacheNamespaceRef
@Case
@ConstructorArgs
@Delete
@DeleteProvider
@Flush
@Insert
@InsertProvider
@Lang
@Many
@MapKey
@Mapper
@One
@Options
@Param
@Property
@Result
@ResultMap
@Results
@ResultType
@Select
@SelectKey
@SelectProvider
@TypeDiscriminator
@Update
@UpdateProvider
01.SQL语句映射
1)@Insert:实现新增功能
@Insert("insert into user(id,name) values(#{id},#{name})")
public int insert(User user);
2)@Select:实现查询功能
@Select("Select * from user")
@Results({
@Result(id = true, column = "id", property = "id"),
@Result(column = "name", property = "name"),
@Result(column = "sex", property = "sex"),
@Result(column = "age", property = "age")
})
List<User> queryAllUser();
3)@SelectKey:插入后,获取id的值
以 MySQL 为例,MySQL 在插入一条数据后,使用 select last_insert_id() 可以获取到自增 id 的值。
@Insert("insert into user(id,name) values(#{id},#{name})")
@SelectKey(statement = "select last_insert_id()",
keyProperty = "id",
keyColumn = "id",
resultType = int,
before = false)
public int insert(User user);
@SelectKey 各个属性含义如下:
statement:表示要运行的 SQL 语句;
keyProperty:可选项,表示将查询结果赋值给代码中的哪个对象;
keyColumn:可选项,表示将查询结果赋值给数据表中的哪一列;
resultType:指定 SQL 语句的返回值;
before:默认值为 true,在执行插入语句之前,执行 select last_insert_id()。值为 flase,则在执行插入语句之后,执行 select last_insert_id()。
4)@Insert:实现插入功能
@Insert("insert into user(name,sex,age) values(#{name},#{sex},#{age}")
int saveUser(User user);
5)@Update:实现更新功能
@Update("update user set name= #{name},sex = #{sex},age =#{age} where id = #{id}")
void updateUserById(User user);
6)@Delete:实现删除功能
@Delete("delete from user where id =#{id}")
void deleteById(Integer id);
7)@Param:映射多个参数
@Param 用于在 Mapper 接口中映射多个参数。
int saveUser(@Param(value="user") User user,@Param("name") String name,@Param("age") Int age);
@Param 中的 value 属性可省略,用于指定参数的别名。
02.结果集映射
@Result、@Results、@ResultMap 是结果集映射的三大注解。
声明结果集映射关系代码:
@Select({"select id, name, class_id from student"})
@Results(id="studentMap", value={
@Result(column="id", property="id", jdbcType=JdbcType.INTEGER, id=true),
@Result(column="name", property="name", jdbcType=JdbcType.VARCHAR),
@Result(column="class_id ", property="classId", jdbcType=JdbcType.INTEGER)
})
List<Student> selectAll();
下面为 @Results 各个属性的含义。
id:表示当前结果集声明的唯一标识;
value:表示结果集映射关系;
@Result:代表一个字段的映射关系。其中,column 指定数据库字段的名称,property 指定实体类属性的名称,jdbcType 数据库字段类型,id 为 true 表示主键,默认 false。
可使用 @ResultMap 来引用映射结果集,其中 value 可省略。
@Select({"select id, name, class_id from student where id = #{id}"})
@ResultMap(value="studentMap")
Student selectById(Integer id);
这样不需要每次声明结果集映射时都复制冗余代码,简化开发,提高了代码的复用性。
03.关系映射
1)@one:用于一对一关系映射
@Select("select * from student")
@Results({
@Result(id=true,property="id",column="id"),
@Result(property="name",column="name"),
@Result(property="age",column="age"),
@Result(property="address",column="address_id",one=@One(select="net.biancheng.mapper.AddressMapper.getAddress"))
})
public List<Student> getAllStudents();
2)@many:用于一对多关系映射
@Select("select * from t_class where id=#{id}")
@Results({
@Result(id=true,column="id",property="id"),
@Result(column="class_name",property="className"),
@Result(property="students", column="id", many=@Many(select="net.biancheng.mapper.StudentMapper.getStudentsByClassId"))
})
public Class getClass(int id);
2.2 附:MyBatisPlus注解
01.MyBatisPlus
a.对比MyBatis
1.更换成MybatisSqlSessionFactoryBean
2.继承一个父接口extends BaseMapper<Student>,之后就可以使用该接口中”已经存在的CRUD方法
3.操作,通过注解将表(字段)-类(属性)
b.接口继承BaseMapper<>,无SQL映射文件
JDBC Dao接口 Dao实现类
MyBatis Mapper接口 SQL映射文件
MyBatis-PLus Mapper接口 extends BaseMapper<Student>,无需编写SQL映射文件
c.扫描器,将MyBatis所有接口转换为Mapper类,默认自动将接口实现
applicationContext.xml
-----------------------------------------------------------------------------------------------------
<!--MyBatis:只写接口,不写实现类-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--MyBatis会自动将接口实现-->
<property name="basePackage" value="org.myslayers.mapper"/>
</bean>
d.获取StudentMapper对象
1.先获取springloc容器再读取StudentMapper..class
2.强制转换
-----------------------------------------------------------------------------------------------------
public static void query(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
StudentMapper studentMapper = context.getBean("studentMapper", StudentMapper.class);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("stu_no",4);
map.put("stu_name","fsf");
//select * from student where stu_no=? and stu_name=?
List<Student> students = studentMapper.selectByMap(map);
System.out.println(students);
}
e.数据设计,直接使用注解,不再像mybatis利用mapper.xml文件指定字段
a.对象属性--表的字段
@Tableld
@TableField
b.对象属性-表的字段:默认表名和类名一致
@TableName("tb_student")
f.命名规范
a.示例
private int stuNo;
private String stuName;
private int stuAge;
SQL:INSERT INTO student stu_no,stu_name,stu_age VALUES (?,?,?)
b.约定
类的是属性:stuName
表的字段:stu_name
遵循"约定”,自动stuName->stu_name
c.自增策略:增加数据,还会将db中自增的主键”回写“到原对象
Studentstudent new Student(stuName:"zz",stuAge:23);
int count studentMapper.insert(student);
System.out.println(student);
-------------------------------------------------------------------------------------------------
Student{stuNo=6,stuName='zz',stuAge=23}
02.MyBatisPlus注解
@TableName
@Tableld
@TableField
---------------------------------------------------------------------------------------------------------
@Version
@EnumValue
@TableLogic
@SqlParser
@KeySequence
@Interceptorlgnore
@OrderBy
2.3 附:Lombok注解
00.全部注解:默认使用非静态,非瞬态的属性,不会涉及到父类的属性和方法
a.@Date
@Getter --类/属性
@Setter --类/属性
@RequiredArgsConstructor --类,包含final和@NonNull注解的成员变量的构造器
@ToString --类
@EqualsAndHashCode --类
默认生成的equals和hashcode方法(不包含继承的父类属性方法),不能对“子类”生成,不适合map、set等集合使用
默认实现没有使用父类属性,若想调用父类的方法,则需要指定callSuper,@EqualsAndHashCode(callSuper=true)
b.常见注解
@NoArgsConstructor --类,无参
@AllArgsConstructor --类,有参
@Builder --类,构造器
@Log4j/@Slf4j --类,提供一个的Logger对象,变量名为log
c.@Accessors
@Data
@Accessors(fluent = true) --类,getter和setter是基础属性名,且setter返回当前对象
public class User {
private Long id;
private String name;
// 生成的getter和setter方法如下,方法体略
public Long id() {}
public User id(Long id) {}
public String name() {}
public User name(String name) {}
}
-----------------------------------------------------------------------------------------------------
@Data
@Accessors(chain = true) --类,链式方法,setter方法返回当前对象
public class User {
private Long id;
private String name;
// 生成的setter方法如下,方法体略
public User setId(Long id) {}
public User setName(String name) {}
}
-----------------------------------------------------------------------------------------------------
@Data
@Accessors(prefix = "p") --类,getter和setter忽视指定前缀(遵守驼峰命名)
class User {
private Long pId;
private String pName;
// 生成的getter和setter方法如下,方法体略
public Long getId() {}
public void setId(Long id) {}
public String getName() {}
public void setName(String name) {}
}
d.@SuperBuilder,1.18版引入
支持继承层次结构中的构建器模式。
自动生成标准的getter、setter、equals()、hashCode()和toString()方法
与Lombok的其他注解兼容
-----------------------------------------------------------------------------------------------------
import lombok.Getter;
import lombok.ToString;
import lombok.experimental.SuperBuilder;
@Getter
@ToString
@SuperBuilder
public class Parent {
private long id;
private String name;
@Getter
@ToString
@SuperBuilder
public static class Child extends Parent {
private String value;
}
}
e.推荐注解
@ApiModel(value = "org-myslayers-entity-RoleMenu")
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@TableName(value = "sys_role_menu")
public class RoleMenu implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.INPUT)
@ApiModelProperty(value = "主键ID")
private Integer id;
/**
* 角色-菜单【角色ID】
*/
@TableField(value = "role_id")
@ApiModelProperty(value = "角色-菜单【角色ID】")
private Long roleId;
/**
* 角色-菜单【菜单ID】
*/
@TableField(value = "menu_id")
@ApiModelProperty(value = "角色-菜单【菜单ID】")
private Long menuId;
}
01.Setter-Getter方法
a.描述
Lombok生成的getter和setter方法在某些情况下与IDE(如IntelliJ IDEA)或框架(如MyBatis)生成的方法不一致,
特别是当属性名的第一个字母小写且第二个字母大写时
b.代码示例
@Data
public class DemoDto {
private String xName;
// 其他属性
}
public class DemoApp {
public static void main(String[] args) {
// 使用 @Data 注解生成的 get, set 方法, X 是大写的
DemoDto dto = new DemoDto();
dto.getXName(); // Lombok生成的方法
// 用IDEA生成的 get, set 方法, x 是小写的
dto.getxName(); // IDEA生成的方法
}
}
c.代码说明
Lombok生成的getter方法是getXName(),而IDEA生成的getter方法是getxName()
这种不一致可能导致框架(如MyBatis)无法正确识别getter和setter方法,导致数据读写失败
d.解决办法
修改属性名字,让第二个字母小写
对于这种特殊的属性,使用IDEA生成getter和setter方法
02.@EqualsAndHashCode和equals()方法
a.描述
当使用@EqualsAndHashCode(callSuper=true)注解时,如果父类是Object,Lombok生成的equals()方法可能会导致意外行为
b.代码示例
@Data
@EqualsAndHashCode(callSuper=true)
public class BaseVO {
private int id;
}
@Data
public class DerivedVO extends BaseVO {
private String name;
}
c.代码说明
如果父类是Object,Lombok生成的equals()方法只会在两个对象是同一个对象时返回true,否则总是返回false,无论它们的属性是否相同
d.解决办法
不使用@EqualsAndHashCode(callSuper=true)注解
去掉callSuper=true,如果父类是Object,推荐使用
重写父类的equals()方法,确保父类不会调用或使用类似实现的Object的equals()
03.@Data注解
a.描述
@Data注解包含@EqualsAndHashCode注解,可能导致子类忽略父类属性的比较
b.代码描述
@Data
public class Parent {
private int a;
}
@Data
public class Child extends Parent {
private int b;
public static void main(String[] args) {
Child child1 = new Child();
Child child2 = new Child();
child1.setA(1);
child2.setA(2);
child1.setB(1);
child2.setB(1);
System.out.println(child1.equals(child2)); // true
}
}
c.代码说明
Lombok生成的equals()方法只比较子类特有的属性,忽略了父类属性的比较,导致两个对象的equals()方法返回true
d.解决办法
使用@EqualsAndHashCode(callSuper=true)注解
自己重写equals()方法
04.@Builder注解
a.描述
当父类和子类都使用@Builder注解时,可能会导致编译错误
b.代码示例
@Getter
@ToString
public class Parent {
private long id;
private String name;
@Builder
@Getter
@ToString
static class Child extends Parent {
private String value;
}
}
c.代码说明
Lombok未考虑父类的字段,只考虑当前子类的字段,导致编译错误
d.解决方案
使用@SuperBuilder注解,同时注解父类和子类。
注意@SuperBuilder和@Builder在父类和子类中不能混用
05.@Data注解的hashCode和equals方法
a.描述
@Data注解默认包含@EqualsAndHashCode注解,可能导致hashCode和equals方法行为不符合预期
b.代码示例
@Data
public class DataTest {
private int code;
private String name;
public DataTest(int code, String name) {
this.code = code;
this.name = name;
}
public static void main(String[] args) {
DataTest dataTest1 = new DataTest(1, "name");
DataTest dataTest2 = new DataTest(1, "name");
System.out.println(dataTest1 == dataTest2); // false
Map<DataTest, String> map = new HashMap<>();
map.put(dataTest1, dataTest1.getName());
map.put(dataTest2, dataTest2.getName());
System.out.println(map.size()); // 1
}
}
c.代码说明
两个对象地址不一样,但由于@Data注解默认包含@EqualsAndHashCode注解,
重写了hashCode和equals方法,导致所有属性相同情况下hashCode相同,hashMap认为是同一个key。
d.解决方案
在需要比较父类属性时,显式使用@EqualsAndHashCode(callSuper=true)注解。
按需使用@Getter和@Setter注解,而不是使用@Data注解
3 核心:CRUD接口
3.1 示例
00.表设计
@TableName("tb_student")
public class Student {
//IdType.AUTO依赖于数据库
@TableId(value = "stu_no", type = IdType.AUTO)
private int stuNo;
private String stuName;
@TableField(value = "stu_age")
private int stuAge;
...
}
01.增:insert
public static void insert(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
StudentMapper studentMapper = context.getBean("studentMapper", StudentMapper.class);
Student student = new Student("zz",23);
int count = studentMapper.insert(student);
System.out.println(count);
System.out.println(student);
}
02.删:deleteById、deleteBatchIds、deleteByMap
public static void delete(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
StudentMapper studentMapper = context.getBean("studentMapper", StudentMapper.class);
int count = studentMapper.deleteById(5);
List<Integer> stuNos = new ArrayList<Integer>();
stuNos.add(2);
stuNos.add(3);
stuNos.add(6);
int count = studentMapper.deleteBatchIds(stuNos);
//stu_no=? and stu_name=?
Map<String, Object> map = new HashMap<String, Object>();
map.put("stu_no",4);
map.put("stu_name","zs");
int count = studentMapper.deleteByMap(map);
System.out.println(count);
}
03.改:updateById
public static void update(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
StudentMapper studentMapper = context.getBean("studentMapper", StudentMapper.class);
//根据主键stuNo更新
Student stu = new Student(6,"sfs",26);
int count = studentMapper.updateById(stu);
System.out.println(count);
}
04.查:selectById、selectBatchIds、selectByMap
public static void query(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
StudentMapper studentMapper = context.getBean("studentMapper", StudentMapper.class);
Student student = studentMapper.selectById(6);
List<Integer> stuNos = new ArrayList<Integer>();
stuNos.add(3);
stuNos.add(4);
stuNos.add(5);
List<Student> students = studentMapper.selectBatchIds(stuNos);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("stu_no",4);
map.put("stu_name","fsf");
//select * from student where stu_no=? and stu_name=?
List<Student> students = studentMapper.selectByMap(map);
System.out.println(students);
}
3.2 BaseMapper接口 / Mapper CRUD 接口
00.介绍
BaseMapper 接口的全限定名称为 com.baomidou.mybatisplus.core.mapper.BaseMapper<T>,该接口提供了插入、修改、删除和查询接口。
MyBatis Plus 提供了通用的 Mapper 接口(即 BaseMapper 接口),该接口对应我们的 DAO 层。
在该接口中,定义了我们常见的方法签名,这样就可以方便我们对表进行操作。
例如:查询(select)、插入(insert)、更新(update)和删除(delete)操作。
-------------------------------------------------------------------------------------------------------------
插入:1个 insert
删除:4个 delete
更新:2个 update
查询:10个 select
01.BaseMapper接口
public interface BaseMapper<T> extends Mapper<T> {
int insert(T entity);
int deleteById(Serializable id);
int deleteByMap(@Param("cm") Map<String, Object> columnMap);
int delete(@Param("ew") Wrapper<T> wrapper);
int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);
int updateById(@Param("et") T entity);
int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);
T selectById(Serializable id);
List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);
T selectOne(@Param("ew") Wrapper<T> queryWrapper);
Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);
List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);
IPage<T> selectPage(IPage<T> page, @Param("ew") Wrapper<T> queryWrapper);
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param("ew") Wrapper<T> queryWrapper);
}
3.3 IService接口 / Service CRUD 接口
00.介绍
除了 BaseMapper 接口,MyBatis Plus 还提供了 IService 接口,该接口对应 Service 层。
MyBatis Plus 的通用 Service CRUD 实现了 IService 接口,进一步封装 CRUD。
为了避免与 BaseMapper 中定义的方法混淆,
该接口使用 get(查询单行)、remove(删除)、list(查询集合)和 page(分页)前缀命名的方式进行区别。
-------------------------------------------------------------------------------------------------------------
保存数据:3个 Save
保存或更新数据:4个 SaveOrUpdate
删除数据:4个 Remove
更新数据:5个 Update
获取单条数据:5个 Get
获取数据列表:10个 List
数据分页查询:8个 Page
统计数据条数:2个 Count
链式查询:3个 Chain
01.IService接口
public interface IService<T> {
boolean save(T entity);
@Transactional(
rollbackFor = {Exception.class}
)
default boolean saveBatch(Collection<T> entityList) {
return this.saveBatch(entityList, 1000);
}
boolean saveBatch(Collection<T> entityList, int batchSize);
@Transactional(
rollbackFor = {Exception.class}
)
default boolean saveOrUpdateBatch(Collection<T> entityList) {
return this.saveOrUpdateBatch(entityList, 1000);
}
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);
boolean removeById(Serializable id);
boolean removeByMap(Map<String, Object> columnMap);
boolean remove(Wrapper<T> queryWrapper);
boolean removeByIds(Collection<? extends Serializable> idList);
boolean updateById(T entity);
boolean update(T entity, Wrapper<T> updateWrapper);
default boolean update(Wrapper<T> updateWrapper) {
return this.update((Object)null, updateWrapper);
}
@Transactional(
rollbackFor = {Exception.class}
)
default boolean updateBatchById(Collection<T> entityList) {
return this.updateBatchById(entityList, 1000);
}
boolean updateBatchById(Collection<T> entityList, int batchSize);
boolean saveOrUpdate(T entity);
T getById(Serializable id);
Collection<T> listByIds(Collection<? extends Serializable> idList);
Collection<T> listByMap(Map<String, Object> columnMap);
default T getOne(Wrapper<T> queryWrapper) {
return this.getOne(queryWrapper, true);
}
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
Map<String, Object> getMap(Wrapper<T> queryWrapper);
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
int count(Wrapper<T> queryWrapper);
default int count() {
return this.count(Wrappers.emptyWrapper());
}
List<T> list(Wrapper<T> queryWrapper);
default List<T> list() {
return this.list(Wrappers.emptyWrapper());
}
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
default IPage<T> page(IPage<T> page) {
return this.page(page, Wrappers.emptyWrapper());
}
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
default List<Map<String, Object>> listMaps() {
return this.listMaps(Wrappers.emptyWrapper());
}
default List<Object> listObjs() {
return this.listObjs(Function.identity());
}
default <V> List<V> listObjs(Function<? super Object, V> mapper) {
return this.listObjs(Wrappers.emptyWrapper(), mapper);
}
default List<Object> listObjs(Wrapper<T> queryWrapper) {
return this.listObjs(queryWrapper, Function.identity());
}
<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);
default IPage<Map<String, Object>> pageMaps(IPage<T> page) {
return this.pageMaps(page, Wrappers.emptyWrapper());
}
BaseMapper<T> getBaseMapper();
default QueryChainWrapper<T> query() {
return new QueryChainWrapper(this.getBaseMapper());
}
default LambdaQueryChainWrapper<T> lambdaQuery() {
return new LambdaQueryChainWrapper(this.getBaseMapper());
}
default UpdateChainWrapper<T> update() {
return new UpdateChainWrapper(this.getBaseMapper());
}
default LambdaUpdateChainWrapper<T> lambdaUpdate() {
return new LambdaUpdateChainWrapper(this.getBaseMapper());
}
}
3.4 ActiveRecord模式
01.步骤
a.继承Model类
@TableName("tb_student")
public class Student extends Model<Student> {
@TableId(type = IdType.AUTO)
private int stuNo;
private String stuName;
private int stuAge;
...
}
b.语法要求:接口
public interface StudentMapper extends BaseMapper<Student> {
}
c.加载IOC容器 + stu.insert/deleteById/updateById
public static void testAR(){
//必须先加载IOC容器,目是为了让AR知道要操作的是数据库在哪里
new ClassPathXmlApplicationContext("applicationContext.xml");
/*
Student stu = new Student("fssf",25);
stu.insert();
*/
/*
Student stu = new Student(4);
stu.deleteById();
*/
/*
Student stu = new Student();
stu.deleteById(5);
*/
/*
Student stu = new Student(6,"hello", 22);
stu.updateById();
*/
Student stu = new Student();
QueryWrapper<Student> wrapper = new QueryWrapper<>();
//面向对象查询
wrapper.lambda().like(Student::getStuName, "a");
//面向SQL查询
//wrapper.like("stu_name","a");
List<Student> students = stu.selectList(wrapper);
System.out.println(students);
}
02.面向对象查询、面向SQL查询
a.面向对象查询
wrapper.lambda().like(Student::getStuName, "a"); // like stu name like '%a%
b.面向SQL查询
wrapper.like("stu_name","a"); // like '%a%'
4 核心:条件构造器:where语句
4.1 QueryWrapper
00.示例
public static void query(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
StudentMapper studentMapper = context.getBean("studentMapper", StudentMapper.class);
/*
//SELECT stu_no,stu_name,stu_age FROM tb_student WHERE stu_no BETWEEN ? AND ?
// AND stu_age >= ?
// AND stu_age <= ?
QueryWrapper<Student> wrapper = new QueryWrapper<Student>();
wrapper.between("stu_no", 3, 5)
.ge("stu_age",20)
.le("stu_age",28)
;
*/
/*
//SELECT stu_no,stu_name,stu_age FROM tb_student WHERE stu_no BETWEEN ? AND ?
// OR
// stu_age >= ?
// AND stu_age <= ?
QueryWrapper<Student> wrapper = new QueryWrapper<Student>();
wrapper.between("stu_no", 3, 5)
.or()
.ge("stu_age",20)
.le("stu_age",28)
;
*/
//SELECT stu_no,stu_name,stu_age FROM tb_student WHERE stu_no BETWEEN ? AND ?
// OR ( stu_age >= ? AND stu_age <= ? )
QueryWrapper<Student> wrapper = new QueryWrapper<Student>();
wrapper.between("stu_no", 3, 5)
.or(i->i.ge("stu_age",20).le("stu_age",28))
;
List<Student> students = studentMapper.selectList(wrapper);
System.out.println(students);
}
4.2 UpdateWrapper
00.示例
public static void update(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
StudentMapper studentMapper = context.getBean("studentMapper", StudentMapper.class);
/*
//UPDATE tb_student SET stu_name=?, stu_age=? WHERE stu_no=?
Student stu = new Student(7, "zc", 25);
int count = studentMapper.updateById(stu);
System.out.println(count);
*/
//UPDATE tb_student SET stu_name=?, stu_age=? WHERE stu_no = ?
Student stu = new Student("fsf",25);
UpdateWrapper<Student> wrapper = new UpdateWrapper<>();
wrapper.eq("stu_no", 5);
int count = studentMapper.update(stu, wrapper);
System.out.println(count);
}
5 核心:代码生成器
01.MyBatis
模板配置文件
student表 -> Student类、Mapper接口、mapper.xml
02.MyBatisPlus
类
student表 -> Student类、Mapper接口、mapper.xml、Service、Controller
6 插件:分页插件
6.1 MP分页拦截器
01.Spring配置
<!--操作MyBatisplus-->
<bean id="sqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<!--数据源-->
<property name="dataSource" ref="dataSource"/>
<!--mybatis.xml-->
<property name="configLocation" value="classpath:mybatis.xml"/>
<!--别名-->
<property name="typeAliasesPackage" value="org.myslayers.entity"/>
<!--插件-->
<property name="plugins" >
<list>
<!--分页插件-->
<bean class="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor"></bean>
<!--性能优化-->
<!--
<bean></bean>
-->
</list>
</property>
</bean>
02.测试
public static void testPage() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
StudentMapper studentMapper = context.getBean("studentMapper", StudentMapper.class);
//使用分页, select * from student;
IPage<Student> page = studentMapper.selectPage(new Page<>(2,2), null);
System.out.println("当前页的属性" + page.getRecords());
System.out.println("当前页的页码" + page.getCurrent());
System.out.println("总数据量" + page.getTotal());
System.out.println("每页数据量" + page.getSize());
}
6.2 攻击 SQL 阻断解析器
01.Spring配置
<!--操作MyBatisplus-->
<bean id="sqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<!--数据源-->
<property name="dataSource" ref="dataSource"/>
<!--mybatis.xml-->
<property name="configLocation" value="classpath:mybatis.xml"/>
<!--别名-->
<property name="typeAliasesPackage" value="org.myslayers.entity"/>
<!--插件-->
<property name="plugins" >
<list>
<!--分页插件、攻击 SQL 阻断解析器-->
<bean class="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor">
<property name="sqlParserList">
<list>
<bean class="com.baomidou.mybatisplus.extension.parsers.BlockAttackSqlParser">
</bean>
</list>
</property>
</bean>
</list>
</property>
</bean>
02.测试“删除全部”
//攻击 SQL 阻断解析器
public static void testDeleteAll() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
StudentMapper studentMapper = context.getBean("studentMapper", StudentMapper.class);
//测试:攻击 SQL 阻断解析器
//wrapper:null 没有where, 即delete from student
studentMapper.delete(null);
}
---------------------------------------------------------------------------------------------------------
报错:exception is org.apache.ibatis.exceptions.PersistenceException:MybatisPlusException:Prohibition of full table deletion
03.测试“更新全部”
//攻击 SQL 阻断解析器:testUpdateAll
public static void testUpdateAll() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
StudentMapper studentMapper = context.getBean("studentMapper", StudentMapper.class);
//update set x=x, x=x 无where
Student stu = new Student("zs", 23);
studentMapper.update(stu,null);
}
-------------------------------------------------------------------------------------------------------------
报错:MybatisPlusException:Prohibition of table update operation
6.3 性能分析
01.Spring配置
<!--操作MyBatisplus-->
<bean id="sqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<!--数据源-->
<property name="dataSource" ref="dataSource"/>
<!--mybatis.xml-->
<property name="configLocation" value="classpath:mybatis.xml"/>
<!--别名-->
<property name="typeAliasesPackage" value="org.myslayers.entity"/>
<!--插件-->
<property name="plugins" >
<list>
<!--分页插件、攻击 SQL 阻断解析器-->
<bean class="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor">
<property name="sqlParserList">
<list>
<bean class="com.baomidou.mybatisplus.extension.parsers.BlockAttackSqlParser">
</bean>
</list>
</property>
</bean>
<!--性能分析-->
<bean class="com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor">
<property name="maxTime" value="100" />
<!--SQL是否格式化 默认false-->
<property name="format" value="true" />
</bean>
</list>
</property>
</bean>
02.测试性能分析
Time:5 ms ID:org.myslayers.mapper.StudentMapper.selectPage
Execute SQL:
SELECT
stu_no,
stu name,
stu_age
FROM
tb_student LIMIT 2,
2]
Time:14 ms ID:org.myslayers.mapper.StudentMapper.selectPage
Execute SOL:
SELECT
stu_no,
stu_name,
stu_age
FROM
tb_student LIMIT 2,
2]
7 插件:乐观锁
7.1 悲观锁
00.汇总
乐观锁:CVS算法(总以为不冲突)
悲观锁:synchorinzed,lock(总以为会冲突)
7.2 乐观锁
01.配置
a.spring xml
<bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"/>
b.spring boot
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
02.注解实体字段@Version
@Version:当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:
1.取出记录时,获取当前 version
2.更新时,带上这个 version
3.执行更新时, set version = newVersion where version = oldVersion
4.如果 version 不对,就更新失败
03.使用
a.数据库增加version字段,并设置为1
略
b.测试:修改成功,version自增1
//乐观锁
public static void testOptimistClock() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
StudentMapper studentMapper = context.getBean("studentMapper", StudentMapper.class);
Student stu = new Student(100,"yy",99);
stu.setVersion(2);
int count = studentMapper.updateById(stu);
if (count>0){
System.out.println("修改成功!");
}else {
System.out.println("修改!并发冲突!已被别人修改了!");
}
}
8 扩展:SQL注入器
00.通过SQL注入器来自定义SQL方法:
1.StudentMapper:声明自定义方法名,继承BaseMapper
public interface StudentMapper extends BaseMapper<Student> {
/**BaseMapper默认17个方法 --> 默认被注入在MP中
*
* 1.编写新方法:deleteAllStudents();//sql语句,默认已有的17个方法
*
* 2.注入:继承抽象类 AbstractSqlInjector,并添加自定义SQL
*
* 3.告知MP:停止使用默认的注入器,而改为使用自己的注入器
*/
public void deleteAllStudents();
}
2.自定义SQL方法:写sq语句+自定义方法名
package org.myslayers.injector.methods;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
public class MyDelete extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
String sql;
SqlMethod sqlMethod = SqlMethod.LOGIC_DELETE;
//真删除
sql = "delete from tb_student where stu_no>3";
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
return this.addDeleteMappedStatement(mapperClass, "deleteAllStudents", sqlSource);
}
}
3.注入器:继承抽象类AbstractSqllnjector,并默认17个+添加自定义SQL
//注入器
public class Myinjector extends AbstractSqlInjector {
@Override
public List<AbstractMethod> getMethodList() {
List<AbstractMethod> methodList = new DefaultSqlInjector().getMethodList();
methodList.add(new MyDelete());
return methodList;
}
}
4.告知MP:停止使用默认的注入器,而改为使用自己的注入器
<bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig">
<!--配置注入器-->
<property name="sqlInjector" >
<bean class="org.myslayers.injector.Myinjector"></bean>
</property>
</bean>
<!--操作MyBatisplus-->
<bean id="sqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<!--告知MP:停止使用默认的注入器,而改为使用自己的注入器-->
<property name="globalConfig" ref="globalConfig"></property>
9 扩展:执行SQL分析打印
01.p6spy 依赖引入
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>最新版本</version>
</dependency>
02.application.yml 配置
spring:
datasource:
driver-class-name: com.p6spy.engine.spy.P6SpyDriver
url: jdbc:p6spy:h2:mem:test
...
03.spy.properties 配置
#3.2.1以上使用
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
#3.2.1以下使用或者不配置
#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 设置 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
#driverlist=org.h2.Driver
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2
10 扩展:字段类型处理器
01.类型处理器
用于 JavaType 与 JdbcType 之间的转换,用于 PreparedStatement 设置参数值和从 ResultSet 或 CallableStatement 中取出一个值,
本文讲解 mybatis-plus 内置常用类型处理器如何通过TableField注解快速注入到 mybatis 容器中。
02.JSON 字段类型
@Data
@Accessors(chain = true)
@TableName(autoResultMap = true)
public class User {
private Long id;
...
/**
* 注意!! 必须开启映射注解
*
* @TableName(autoResultMap = true)
*
* 以下两种类型处理器,二选一 也可以同时存在
*
* 注意!!选择对应的 JSON 处理器也必须存在对应 JSON 解析依赖包
*/
@TableField(typeHandler = JacksonTypeHandler.class)
// @TableField(typeHandler = FastjsonTypeHandler.class)
private OtherInfo otherInfo;
}
03.该注解对应了 XML 中写法为
<result column="other_info" jdbcType="VARCHAR" property="otherInfo" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler" />
11 扩展:逻辑删除
01.增加字段
新增logic_delete字段
---------------------------------------------------------------------------------------------------------
1ogic-delete-value:1#逻辑已删除值(默认为1)
logic-not-delete-value:0#逻辑末删除值(默认为0)
02.配置
<bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig">
<!--逻辑删除logic-->
<property name="dbConfig" >
<bean class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig">
<property name="logicDeleteValue" value="1"/>
<property name="logicNotDeleteValue" value="0"/>
</bean>
</property>
</bean>
<!--操作MyBatisplus-->
<bean id="sqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<!--全局配置globalConfig-->
<property name="globalConfig" ref="globalConfig"/>
03.实体类字段加上@TableLogic注解
//如果你的默认值和mp默认的一样,该配置可无
//逻辑删除,如果没有该字段添加,并与数据库字段对应
@TableLogic
private Integer logicDelete;
04.测试
public static void testDelete() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
StudentMapper studentMapper = context.getBean("studentMapper", StudentMapper.class);
//删除全部
studentMapper.delete(null);
}
---------------------------------------------------------------------------------------------------------
Time:10 ms ID:org.myslayers.mapper.StudentMapper.delet
Execute SQL:
UPDATE
tb_student
SET
logic_delete=1
WHERE
logic_delete=0
12 扩展:表名前缀
01.配置
<bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig">
<!--逻辑删除logic-->
<property name="dbConfig" >
<bean class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig">
<property name="logicDeleteValue" value="1"/>
<property name="logicNotDeleteValue" value="0"/>
<!--表名前缀-->
<property name="tablePrefix" value="tb_"/>
</bean>
</property>
</bean>
02.开启keepGlobalPrefix = true
@TableName(value = "student", keepGlobalPrefix = true)
public class Student extends Model<Student> {
...
}
13 扩展:自动填充功能
13.1 MySQL,默认支持自增
01.注解填充字段
public enum FieldFill {
/**
* 默认不处理
*/
DEFAULT,
/**
* 插入填充字段
*/
INSERT,
/**
* 更新填充字段
*/
UPDATE,
/**
* 插入和更新填充字段
*/
INSERT_UPDATE
}
---------------------------------------------------------------------------------------------------------
@TableField(fill = FieldFill.INSERT_UPDATE)
private String stuName;
02.自定义实现类 MyMetaObjectHandler
package org.myslayers.meta;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
System.out.println("start insert fill ....");
//面向对象
this.setInsertFieldValByName("stuName", "zhangsan", metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
System.out.println("start update fill ....");
//面向对象
this.setUpdateFieldValByName("stuName", "lisi", metaObject);
}
}
03.配置
<!--全局配置-->
<bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig">
<!--逻辑删除logic-->
<property name="dbConfig" >
<bean class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig">
<property name="logicDeleteValue" value="1"/>
<property name="logicNotDeleteValue" value="0"/>
<!--表名前缀-->
<property name="tablePrefix" value="tb_"/>
</bean>
</property>
<!--将填充器放入配置-->
<property name="metaObjectHandler" ref="MapperScannerConfigurer"/>
</bean>
<!--自动填充,添加到IOC容器-->
<bean id="MapperScannerConfigurer" class="org.myslayers.meta.MyMetaObjectHandler"/>
04.测试
//自动填充
public static void testInsert() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
StudentMapper studentMapper = context.getBean("studentMapper", StudentMapper.class);
//stu_no:自动 age:33 name:没写 other:没写
Student stu = new Student();
stu.setStuAge(33);
studentMapper.insert(stu);
}
13.2 Oracle,Sequence模拟自增
01.jar:添加oracle到mvn
mvn install:install-file -DgroupId=ojdbc -DartifactId=ojdbc7 -Dversion=7.0.0.1 -Dpackaging=jar -Dfile=ojdbc7.jar
02.配置pom.xml
<!--oracle-->
<dependency>
<groupId>ojdbc</groupId>
<artifactId>ojdbc7</artifactId>
<version>7.0.0.1</version>
</dependency>
03.准备数据:主键,序列sequence
create table tb_student(
stu_no number,
stu_name varchar(10),
stu_age number,
other varchar(10)
);
-- 增加主键
alter table tb_student add constraint PK_STUNO primary key(stu_no);
-- 创建序列: 1开始,步长1
create sequence seq_stu start with 1 increment by 1;
04.主键生成策略、自增字段与序列绑定
// 将本类自增字段与Oracle中序列绑定
@KeySequence(value = "seq_stu", clazz = Integer.class)
public class Student extends Model<Student> {
// oracle没有自增,用序列实现
@TableId(value = "stu_no", type = IdType.INPUT)
05.配置自增策略
<!--全局配置-->
<bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig">
<!--逻辑删除logic-->
<property name="dbConfig" >
<bean class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig">
<property name="logicDeleteValue" value="1"/>
<property name="logicNotDeleteValue" value="0"/>
<!--表名前缀-->
<property name="tablePrefix" value="tb_"/>
<!--将oracleKeyGenerator放入配置-->
<property name="keyGenerator" ref="oracleKeyGenerator"/>
</bean>
</property>
<!--将填充器放入配置-->
<property name="metaObjectHandler" ref="MapperScannerConfigurer"/>
</bean>
<!--oracleKeyGenerator-->
<bean id="oracleKeyGenerator" class="com.baomidou.mybatisplus.extension.incrementer.OracleKeyGenerator"/>
06.测试
//自动填充:oracle
public static void testInsert() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
StudentMapper studentMapper = context.getBean("studentMapper", StudentMapper.class);
//stu_no:自动 age:33 name:没写 other:没写
Student stu = new Student();
stu.setStuAge(33);
studentMapper.insert(stu);
}
07.支持父类定义@KeySequence子类继承使用
@KeySequence(value = "seq_stu", clazz = Integer.class)//将本类自增字段与Oracle中序列绑定
public abstract class Parent extends Model<Student> {
}
public class Student extends Parent {
}