Springboot 项目 Spring Data JPA 与 Mybatis 的混用 时间: 2018-10-11 18:35 分类: JAVA Web,Spring ####前言 以前在项目中,都是单独的使用某种 ORM 或者其他的数据库操作框架来进行数据库操作。 那么在项目中同时使用 Hibernate 与 Mybatis 会不会出现问题呢? ####分析 一开始最容易想到的就是事务问题,如果一个业务方法中需要用到事务,并且方法中同时使用 Hibernate 与 Myabtis 来操作数据库,会不会出现事务无法回滚? 之所以有这样的考虑疑问是因为 Hibernate 与 Mybatis 在同一个业务方法中使用的是不同的 JDBC Connection。 其次,就是数据源的问题,Hibernate 与 Mybatis 是共用一个 DataSource 还是分别使用一个数据源? 最后,Dao 的设计问题,假设上面的问题都不是问题,那么最后就是如何优雅地设计 Dao 接口。 ####实践 这里以一个简单的操作 User 表来做测试。 首先,新建一个 Sptingboot 项目: ![微信截图_20181011181555.png][1] 导入到 Idea,新建包以及类与接口,最终项目结构如下: ![微信截图_20181011181806.png][2] `application.properties`如上图所示,竟然是要同时使用`Hibernate`与`Mybatis`,那么久直接把它们两个都配上试试。 先来看看实体类`User`: ```java package net.che_mi.hmtest.entity; import javax.persistence.*; @Entity(name = "tb_user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column private String name; @Column private Integer age; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } } ``` 和单独使用`Spring Data JPA`时没什么区别。 再看看`Repository`与 Mybatis 的`Mapper`,`UserRepository`: ```java package net.che_mi.hmtest.dao.hibernate; import net.che_mi.hmtest.entity.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface UserRepository extends JpaRepository { } ``` `UserMapper.java`: ```java package net.che_mi.hmtest.dao.mybatis; import net.che_mi.hmtest.entity.User; import org.springframework.stereotype.Repository; import java.util.List; @Repository public interface UserMapper { List selectAll(); void save(User user); } ``` `UserMapper.xml`: ```xml select * from tb_user insert into tb_user (name, age) values (#{name}, #{age}) ``` 以上的一些配置与代码都和单独地使用`Spring Data JPA`或者`Mybatis`没什么两样,那么项目能不能跑起来呢? 直接运行发现没有问题。 再试试同时使用`UserRepository`与`UserMapper`操作数据也没有任何问题。 至于事务问题,最后再说,现在竟然同时使用没有问题,那么如何优雅地使用这两个数据库操作接口? 显然,如果在一个`Service`里面同时注入这两个`Dao`接口是没有问题的,但是不够优雅,注入两个不同的接口就意味着有两个对象名称,每次使用还要去看看方法是在哪个接口里面。 所以我的做法就是使用组合模式再封装一层,也就是上面项目结构图中的`UserDao`类,当然,你也可以把`UserDao`做成接口,然后实现它,我这里为了方便就直接定义了一个`UserDao`类: ```java package net.che_mi.hmtest.dao; import net.che_mi.hmtest.dao.hibernate.UserRepository; import net.che_mi.hmtest.dao.mybatis.UserMapper; import net.che_mi.hmtest.entity.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.List; @Component public class UserDao { @Autowired private UserMapper userMapper; @Autowired private UserRepository userRepository; /*** * 使用 Hibernate 保存用户 * @param user */ public void saveUseJpa(User user) { userRepository.save(user); } /*** * 使用 Mybatis 保存用户 * @param user */ public void saveUseMybatis(User user) { userMapper.save(user); } public List getAll() { return userMapper.selectAll(); } } ``` 然后我们的`UserServiceImpl`中就能这样使用: ```java package net.che_mi.hmtest.service.impl; import net.che_mi.hmtest.dao.UserDao; import net.che_mi.hmtest.entity.User; import net.che_mi.hmtest.service.IUserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.transaction.Transactional; import java.util.List; @Service public class UserServiceImpl implements IUserService { @Autowired private UserDao userDao; @Override public List getAllUser() { return userDao.getAll(); } @Override @Transactional public void saveUser(User user) { userDao.saveUseJpa(user); userDao.saveUseMybatis(user); //int x = 1 / 0; //测试事务 } } ``` 这样一来我们在代码中就只要注入`UserDao`就行了。 最后一个问题就是数据库事务,注意看上面`UserServiceImpl`中的`saveUser()`方法,方法名上面使用`@Transactional`开启事务,方法里面分别调用`saveUseJpa()`与`saveUseMybatis()`来同时使用`Hibernate`与`Mybatis`,然后加上一行异常代码:`int x = 1 / 0;`,观察数据库发现没有一条数据插入成功,即事务生效。 [1]: https://0o0.me/usr/uploads/2018/10/3820324765.png [2]: https://0o0.me/usr/uploads/2018/10/3001949061.png 标签: 无
其实这里的UserDao就相当于一个@Repository咯?