图源:
虽然上篇文章JdbcTemplate
并不是很好用。
因此,本篇文章将介绍一个更好用的数据库连接组件MyBatis-Plus,并展示如何用在我们的示例中用MyBatis-Plus
取代JdbcTemplate
完成相关数据库操作。
你可以通过获取本篇文章用于修改的基础示例代码。
什么是 MyBatis-Plus
MyBatis是一个优秀的持久层框架,可以利用它创建实体层对数据库的映射(其作用类似各种ORM框架)。
而 MyBatis-Plus 是在MyBatis的基础上发展而来,相比于MyBatis,无需配置各种XML文件,更容易使用。
MyBatis-Plus是一个国人开发的框架,所以文档资料很容易查看和获取,其官方网站为:
因此这里不做过多介绍,直接看如何在我们的示例项目中使用MyBatis-Plus。
添加依赖
与其它第三方组件类似,需要先添加依赖:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
目前最新的版本是3.5.1。
Model
和其它ORM框架一样,为了建立对数据库的映射关系,需要给实体类添加注解:
package cn.icexmoon.my_first_app.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
"user")
(public class User {
type = IdType.AUTO)
( private Long id;
private String name;
private Integer age;
}
@TableName
注解指定表名,@TableId
注解指定主键,@TableField
注解指定普通表字段。@TableId
注解有一个type
属性,是一个枚举值,可以用来指定主键类型。比如这里用IdType.AUTO
指定主键是自增的。
Mapper
可以添加一个Mapper
接口作为对数据库的映射,我们可以通过操作这个接口来操作数据库:
package cn.icexmoon.my_first_app.mapper;
import cn.icexmoon.my_first_app.model.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface UserMapper extends BaseMapper<User> {
}
Mapper
接口需要继承自BaseMapper<T>
接口,这里的类型参数T
必须是对应的实体类,这里就是User
。
为了能让MyBatis Plus扫描到Mapper
,还需要在入口类上添加一个@MapperScan
注解:
package cn.icexmoon.my_first_app;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
"cn.icexmoon.my_first_app.mapper")
(public class MyFirstAppApplication {
public static void main(String[] args) {
SpringApplication.run(MyFirstAppApplication.class, args);
}
}
这里@MapperScan
的value
属性应该指定为Mapper
接口所在的包名。
接下来我们只需要修改Service
层,让UserService
使用Mapper
操作数据库即可:
package cn.icexmoon.my_first_app.service;
import cn.icexmoon.my_first_app.mapper.UserMapper;
import cn.icexmoon.my_first_app.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
public class UserService {
private UserMapper userMapper;
public long addUser(User user) {
userMapper.insert(user);
return user.getId();
}
public void deleteUser(long id) {
userMapper.deleteById(Long.valueOf(id));
}
public List<User> getUsers() {
return userMapper.selectList(null);
}
public User getUser(long id) {
return userMapper.selectById(Long.valueOf(id));
}
public void updateUser(User user) {
userMapper.updateById(user);
}
}
这里对UserMapper
的调用都比较简单,所以不一一说明。需要说明的是,通过UserMapper.insert
方法添加数据后,只需要通过User.getId
就可以获取到自增主键,因为我们已经在实体类中通过注解指定了主键对应的属性以及其类型为自增。
可以看到,使用MyBatis Plus实现相同的功能相比JDBCTemplate
要容易很多,代码量也少很多。
更多的
Mapper
接口调用方式可以阅读。需要注意的是,MyBatis Plus中很多类似于
selectById
这样的方法,接受的都是一个Serializable
类型的参数,所以是不能传入基础类型的,需要使用包装类进行转换。
Service
实际上除了通过Mapper
操作数据库,MyBatis Plus还支持利用Mapper
创建简单的Service
。
这里为了更好的复用代码,不删除已有的UserService
实现,添加一个UserServiceInterface
接口:
package cn.icexmoon.my_first_app.service;
import cn.icexmoon.my_first_app.model.User;
import java.util.List;
public interface UserServiceInterface {
long addUser(User user);
void deleteUser(long id);
List<User> getUsers();
User getUser(long id);
void updateUser(User user);
}
UserService
继承该接口:
public class UserService implements UserServiceInterface {
...
}
UserController
使用UserServiceInterface
接口而非具体实现:
"/user")
(public class UserController {
private UserService userService;
private UserServiceInterface userServiceInterface;
public UserController(UserService userService){
userServiceInterface = userService;
}
...
}
UserController
中各种方法都需要修改为使用userServiceInterface
而非userService
,这里不一一展示。
这里需要注意的是,因为要通过UserController
的构造器来为userServiceInterface
指定一个具体实现,所以这里不再通过为属性添加@Autowired
注解的方式,而是直接为构造器添加@Autowired
注解来注入UserService
对象。
如果不这么做,就会产生
NULLPointException
,原因是@Autowired
标记的属性注入发生在构造器调用之后,所以userServiceInterface
不会被正确初始化。
这里可以测试一下当前重构后的代码是否有问题。
下面使用MyBatis Plus
创建Service
层,并在Controller
中进行调用。
要用MyBatis Plus
创建Service
,必须要先创建一个从IService
扩展的接口:
package cn.icexmoon.my_first_app.service;
import cn.icexmoon.my_first_app.model.User;
import com.baomidou.mybatisplus.extension.service.IService;
interface UserServiceMP extends IService<User> {
}
然后利用该接口创建一个Service
:
package cn.icexmoon.my_first_app.service;
import cn.icexmoon.my_first_app.mapper.UserMapper;
import cn.icexmoon.my_first_app.model.User;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import java.util.List;
public class UserServiceMPImpl extends ServiceImpl<UserMapper, User> implements UserServiceMP,UserServiceInterface{
public long addUser(User user) {
this.save(user);
return user.getId();
}
public void deleteUser(long id) {
this.removeById(Long.valueOf(id));
}
public List<User> getUsers() {
return this.list();
}
public User getUser(long id) {
return this.getById(Long.valueOf(id));
}
public void updateUser(User user) {
this.updateById(user);
}
}
UserServiceMPImpl
继承自ServiceImpl<Mapper<T>, T>
,这里类型参数Mapper<T>
对应的是Mapper
接口,T
是实体类。该类还需要实现我们之前创建的UserServiceMP
接口。
这里实现UserServiceInterface
接口并不是通过MyBatis Plus
生成Service
的习惯做法,只不过是我们的示例项目之前重构旧代码的需要。
因为UserServiceMPImpl
实现了UserServiceInterface
接口,所以可以很容易地在Controller
中替换UserServiceInterface
的实现:
"/user")
(public class UserController {
private UserService userService;
private UserServiceInterface userServiceInterface;
public UserController(UserService userService, UserServiceMPImpl userServiceMPImpl){
userServiceInterface = userServiceMPImpl;
}
...
}
这里不再使用
UserService
,应当将其删除,不过出于比较两者实现的考虑,没有这么做。因为旧代码的关系,我这里的
Service
层命名有些混乱,可以用UserService
作为接口名称,用UserServiceImpl
作为具体实现类的命名,用UserServiceMp
作为使用MyBatis Plus
定义的Service
接口,用UserServiceMpImpl
作为对应的实现类。。
现在再试一下,会发现和原来的实现没有任何区别。
具体使用Service
还是Mapper
取决于你,其实两者提供的功能是类似的。
更多的Service
接口调用方式可以阅读。
今天的内容就到这里了,谢谢阅读。
文章评论