SpringBoot整合MyBatis框架

SpringBoot整合MyBatis框架

我们很多应用,访问数据库的方式都是JDBC等等,这些非常麻烦而又繁琐的操作,为了使得这个方式得到更好的优化,人们便开始对上帝有所诉求,上帝感到了程序猿的不幸,为了平衡各个物种的差别,同时也得给达尔文一个面子,于是诞生了MyBatis(瞎说)。

MyBatis

讲到MyBatis,就先讲明这是什么吧。它是一个主流的ORM框架。那ORM又是什么呢?

对象-关系映射(Object-Relational Mapping,简称ORM),面向对象的开发方法是当今企业级应用开发环境中的主流开发方法,关系数据库是企业级应用环境中永久存放数据的主流数据存储系统。对象和关系数据是业务实体的两种表现形式,业务实体在内存中表现为对象,在数据库中表现为关系数据。内存中的对象之间存在关联和继承关系,而在数据库中,关系数据无法直接表达多对多关联和继承关系。因此,对象-关系映射(ORM)系统一般以中间件的形式存在,主要实现程序对象到关系数据库数据的映射。

简而言之,可以通过ORM框架去更方便的操控数据库。

MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

Hibernate是全自动ORM框架,而Mybatis是半自动的。 hibernate完全可以通过对象关系模型实现对数据库的操作,拥有完整的JavaBean对象与数据库的映射结构来自动生成sql。 而mybatis仅有基本的字段映射,对象数据以及对象实际关系仍然需要通过手写sql来实现和管理。

无论是Mybatis、Hibernate都是ORM的一种实现框架,都是对JDBC的一种封装。

最原始的MyBatis

先加入pom依赖
1
2
3
4
5
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
配置文件
1
2
3
4
5
6
7
8

spring.datasource.url=jdbc:mysql://localhost:3306/springdatajpa?useSSL=false&serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8

spring.datasource.username=root

spring.datasource.password=qwe123456

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

定义好要连接的数据库属性,这里涉及到Spring的AOP,这些都是基础配置了。

实体类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class User implements Serializable{

private static final long serialVersionUID = 1L;

private int id ;
private String loginName ;
private String username ;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getLoginName() {
return loginName;
}
public void setLoginName(String loginName) {
this.loginName = loginName;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}

}

也可以用插件,省略掉写这些get和set哦,后面会讲。

SQL的实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public interface UserRepository {

@Insert("insert into tb_user(login_name ,username ,password) "
+ "values (#{loginName},#{username},#{password})")
public int insertUser(User user);

/**
* 插入数据获取主键
*/
@Insert("insert into tb_user(login_name ,username ,password) "
+ "values (#{loginName},#{username},#{password})")
@Options(useGeneratedKeys=true,keyProperty="id",keyColumn="id")
public void insertGetKey(User user);


@Select("select * from tb_user where username = #{username}")
// 引用id="userResult"的@Results
@ResultMap("userResult")
public User selectByUsername(@Param("username") String username);

@Select("select * from tb_user")
// @Results用于映射对象属性和数据库列,常用于对象属性和数据库列不同名情况
@Results(id="userResult",value={
@Result(id=true,column="id",property="id"),
@Result(column="login_name",property="loginName"),
@Result(column="password",property="password"),
@Result(column="username",property="username")
})
public List<User> findAll();


@Delete("delete from tb_user where id=#{id}")
public void delete(final Integer id);


@Select("select * from tb_user where id=#{id}")
// 引用id="userResult"的@Results
@ResultMap("userResult")
public User findUserById(int id);

@Update("update tb_user set username=#{username}, login_name=#{loginName} where id=#{id}")
public void update(final User user);
}

这里是一个接口,所有的SQL实现通过注解写在函数前面,就拥有了这些功能。

服务层
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Service
public class UserService {

// 注入UserRepository
@Resource
private UserRepository userRepository;

public int insertUser(User user){
return userRepository.insertUser(user);
}

public User selectByUsername(String username){
return userRepository.selectByUsername(username);
}

public List<User> findAll(){
return userRepository.findAll();
}

public void insertGetKey(User user) {
// 数据插入成功以后,Mybatis框架会将插入成功的数据主键存入到user对象中去
userRepository.insertGetKey(user);
}

public void update(User user) {
userRepository.update(user);
}

public void delete(Integer id) {
userRepository.delete(id);
}
}

服务层并不需要做些什么,仅仅是注入持久层便可。持久层会使用它的方法,再结合注解去完成查找或查询操作。

控制层
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@RestController
@RequestMapping("/user")
public class UserController {

// 注入UserService
@Resource
private UserService userService;

@RequestMapping("/insertUser")
public String insertUser(User user){
return "插入数据["+userService.insertUser(user)+"]条";
}

@RequestMapping("/insertGetKey")
public User insertGetKey(User user) {
userService.insertGetKey(user);
return user ;
}

@RequestMapping("/selectByUsername")
public User selectByUsername(String username){
return userService.selectByUsername(username);
}

@RequestMapping("/findAll")
public List<User> findAll(){
return userService.findAll();
}

@RequestMapping("/update")
public void update(User user) {
userService.update(user);
}

@RequestMapping("/delete")
public void delete(Integer id) {
userService.delete(id);
}
}

我们使用的@Resource可以寻找服务层的类去注入,从结构来看,一般都是从控制层往下直到持久层。

启动器
1
2
3
4
5
6
7
8
9
@MapperScan("com.my.data07mybatis.repository")
@SpringBootApplication
public class Data07mybatisApplication {

public static void main(String[] args) {
SpringApplication.run(Data07mybatisApplication.class, args);
}

}

最后别忘了在启动器前面加入@MapperScan,它会扫描在这个包下的所有类,并将其识别为MyBatis的Mapper类,这也是MyBatis独有的注解。

XML型MyBatis

使用xml文件去完成mybatis的各种SQL,有利于集中的SQL编写和控制,使我们能够更好的完成业务,大部分公司都在用这个写法。

实体类
1
2
3
4
5
6
7
8
@Data
@Alias("user")
public class User {
int id;
String user_name;
int sex;
String note;
}

在引入了Lombok之后,写一个类只需要在上面加一个@Data注解便可以了,会自动生成get和set方法。

mapper类
1
2
3
4
public interface userMapper {

User find(int id );
}

只需要做个接口就可以了,写好要做的事件的函数头便可,其他都不用。

不过同样的,也需要在启动器中加入

1
@MapperScan("com.example.mybatis2.mapper")

和之前的比起来,少了个SQL语句的编写,那么SQL不用写怎么知道要干什么呢?当然不是不用,而是使用XML文件去代替:

1
2
3
4
<mapper namespace="com.example.mybatis2.mapper.userMapper">
<select id="find" resultType="user" parameterType="int">
select * from t_user where id=#{id}</select>
</mapper>

这便是一个SQL语句,由namespace定位mapper类,由id确定方法头,由parametertype确定传入参数类型,而resulttype则是返回值类型啦。

记得要放在resource文件的mapper文件下哦,不然扫描不到的,具体可以根据自己的需求,在application.yml里面改。

业务层和控制层
1
2
3
4
5
6
7
8
9
10
@Service
public class userService{

@Autowired
private userMapper user;

public User find(int id) {
return user.find(id);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
@RestController
@RequestMapping("/user")
public class userController {

@Autowired
private userService user;

@RequestMapping("/find")
public User find(int id ){

return user.find(id);
}
}

和上面差不多,这里省略了其他方法。

同样的,也需要在启动器中加入MapperScan(),去扫描dao层(持久层)的数据哦。

测试

在浏览器输入:

1
http://localhost:8888/user/find?id=1

便看到结果了:

但,这样还是太麻烦了,咱们还是用更偷懒的办法吧。

高级偷懒法:MyBatis-Puls

MyBatis-Puls,可以让你不写SQL哦。。。

请看:

在pom文件中加入MyBatis-Puls依赖::
1
2
3
4
5
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.6</version>
</dependency>

MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

建议在编程的时候有个好习惯,多加点插件。

1
2
3
4
5
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

lombok是个好东西,谁用谁知道。

application.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mybatis-plus:
mapper-locations: classpath:/mapper/*Mapper.xml
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/springtest?useSSL=false&serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8
driver-class-name: com.mysql.cj.jdbc.Driver
tomcat:
max-idle: 10
max-wait: 10000
max-active: 50
initial-size: 5
server:
port: 8888
config的配置:
1
2
3
@Configuration
@MapperScan("com.example.mybatis.mapper")
public class MyBatisConfig {}
UserMapper
1
2
3
4
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mybatis.mapper.UserMapper">
</mapper>

其实不加入这个也可以,没有影响。

建立数据库
1
2
3
4
5
6
7
CREATE TABLE tbl_user`
(
user_id BIGINT(20) NOT NULL COMMENT '主键ID',`
user_name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',`
user_age INT(11) NULL DEFAULT NULL COMMENT '年龄',`
PRIMARY KEY (user_id)`
) charset = utf8;`

业务编写

实体类
1
2
3
4
5
6
7
8
9
@Data
@TableName("tbl_user")
//@Alias("name")
public class User {
@TableId(value = "user_id")
private Long userId;
private String userName;
private Integer userAge;
}

@Data能够自动构造get和set方法。

@TableName进行绑定操作

同时也可以使用@Alias去指定别名

Mapper类
1
public interface UserMapper extends BaseMapper<User> {}

接口什么都不需要不用写。

Service接口
1
2
3
4
5
6
7
public interface UserService extends IService<User> {
int insertUser( User user );
int updateUser( User user );
int deleteUser( User user );
User findUserByName( String userName );
IPage getUserPage(Page page, User user );
}

在服务层接口定义好要进行的操作。

实现Service层
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Service
@AllArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
// 增
@Override
public int insertUser(User user) {
return baseMapper.insert( user );
}

// 改
@Override
public int updateUser(User user) {
return baseMapper.updateById( user );
}

// 删
@Override
public int deleteUser(User user) {
return baseMapper.deleteById( user.getUserId() );
}

// 查
@Override
public User findUserByName( String userName ) {
return null;
}

@Override
public IPage getUserPage(Page page, User user) {
return null;
}
}

可以发现,这里的增删改查,通通都不用写SQL,简直人类福音啊。因为大部分繁琐的SQL语句,都被封装在baseMapper里面了。

Controller层

最后的就是控制层了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@RestController
@RequestMapping("/user")
public class UserContorller {

@Autowired
private UserService userService;

// 增
@PostMapping( value = "/insert")
public Object insert( @RequestBody User user ) {
return userService.insertUser( user );
}

// 改
@PostMapping( value = "/update")
public Object update( @RequestBody User user ) {
return userService.updateUser( user );
}

// 删
@PostMapping( value = "/delete")
public Object delete( @RequestBody User user ) {
return userService.deleteUser( user );
}

// 查
@GetMapping( value = "/getUserByName")
public Object getUserByName( @RequestParam String userName ) {
return userService.findUserByName( userName );
}
}

这样就好了,开始尝试一下把。

先打开postman,在输入:

多输入几条,最后再去数据库查看一下。

果然都输入进去了,那么再试试更改:

看看数据库:

发现也成功了,删除就不演示了。这样的方式,省略了大量的SQL语句,同样将数据传入了数据库。

是不是一点SQL都不用写,只用写实体类,再调用方法就行了。很棒吧。

还是太麻烦了,我懒,我实体类都不想写,我想让实体类都自己生成。

行吧,我告诉你一个更好的办法,自动生成代码!

究极偷懒法:Mybatis-Generator

这个能够让你自动生成代码,连实体类都不用写哦。

方法如下:

引入依赖

1
2
3
4
5
6
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.7</version>
<scope>provided</scope>
</dependency>

插件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.7</version>

<configuration>
<configurationFile>src/main/resources/mybatis-generator.xml</configurationFile>
<overwrite>true</overwrite>
</configuration>

<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
</dependencies>
</plugin>

配置

MyBatis Generator 也需要一个 xml格式的配置文件,该文件的位置配在了上文 引入 MyBatis Generator Maven 插件的 xml配置里,即 src/main/resources/mybatis-generator.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?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>

<context id="MySql" defaultModelType="flat">

<plugin type="org.mybatis.generator.plugins.SerializablePlugin" />

<jdbcConnection
driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/springtest?serverTimezone=UTC"
userId="root"
password="123456" />

<javaModelGenerator targetPackage="com.example.mybatis4.entity" targetProject="src/main/java"></javaModelGenerator>

<sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources"></sqlMapGenerator>

<javaClientGenerator targetPackage="com.example.mybatis4.mapper" targetProject="src/main/java" type="XMLMAPPER"></javaClientGenerator>

<table tableName="tbl_user">
<property name="modelOnly" value="false"/>
</table>

</context>

</generatorConfiguration>

上面 xml中几个关键的配置简介如下:

  • jdbcConnection:数据库连接配置
  • javaModelGenerator:指定自动生成的 POJO置于哪个包下
  • sqlMapGenerator:指定自动生成的 mapper.xml置于哪个包下
  • javaClientGenerator:指定自动生成的 DAO接口置于哪个包下
  • table tableName:指定数据表名,可以使用_和%通配符

记得一定要配置好,具体可以对照着配置。

运行

双击右边的MyBatis Generator:

看看效果吧:

这样,就连实体类都自动生成了。

我还想。。。让数据库自己跑到后端,自己动,可以吗?

项目地址:

https://github.com/Antarctica000/SpringBoot/tree/master/mybatis

https://github.com/Antarctica000/SpringBoot/tree/master/mybatis2

https://github.com/Antarctica000/SpringBoot/tree/master/mybatis3

https://github.com/Antarctica000/SpringBoot/tree/master/mybatis4