30分钟带你了解Springboot与Mybatis整合最佳实践
前言:Springboot怎么使用想必也无需我多言,Mybitas作为实用性极强的ORM框架也深受广大开发人员喜爱,有关如何整合它们的文章在网络上随处可见。但是今天我会从实战的角度出发,谈谈我对二者结合与使用的最佳实践。
一、依赖与pom
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.4.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.1</version> </dependency> </dependencies>
目前SpringBoot官方的最新版本是2.0.4.RELEASE我们就以这个版本为基础,2.0以下版本可能会有些区别这里不多解释。
二、创建配置文件和启动类
Spring官方推荐使用yml文件,既然是最佳实践我们就按照官方的要求来做。
application.yml
server:
port: 8090
spring:
datasource:
mimas:
driverClassName: com.mysql.jdbc.Driver
jdbcUrl: jdbc:mysql://192.168.56.101:3306/mimas
username: root
password: 12345678
logging:
level:
com.learnhow.springboot.mybatis.dao: debug
解释一下三个部分的含义:
(1)server:代表当前服务通过8090端口访问。
(2)spring:配置了一个名为mimas的数据源,如果项目需要多个数据源可以按照这样的方式将数据源配置成不同的名称。
(3)logging:定义dao包下的日志记录级别为debug,标准输出会显示sql语句(这一点对开发还是很重要的)
Application.java
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
三、xml文件与接口
Springboot与Mybatis整合以后可以使用annotation(注解)和xml(配置文件)两种方式编写sql语句,我推荐的做法是后者。就目前我接触到的项目来说,项目部署环境都比较严格,往往修改一个BUG到重新部署完成少则2个小时,多则数天。而很多BUG有时候仅仅需要修改几条SQL语句。如果采用配置文件的方式,这类问题只需要在服务器上修改一下文件然后再重启一下服务就能完成。其次,我个人也很不喜欢Java代码和SQL代码混再一起开发方式,既不美观也不便于维护。所以通常在项目初期我都会尽量避免这类为以后埋坑的行为。
以下是一个典型的xml配置:
<?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.learnhow.springboot.mybatis.dao.mimas.UserDao"> <resultMap type="User" id="UserMap"> <id column="id" property="id" jdbcType="BIGINT" /> <result column="user_name" property="username" jdbcType="VARCHAR" /> <result column="user_age" property="age" jdbcType="INTEGER" /> <result column="user_gender" property="gender" jdbcType="INTEGER" /> <result column="ep_id" property="enterpriseId" jdbcType="BIGINT" /> </resultMap> <select id="getAll" resultType="User"> select * from user_t </select> <select id="getOne" resultType="User" parameterType="Long"> select * from user_t t where t.id = #{id} </select> <insert id="saveUsers"> insert into user_t(user_name, user_age, user_gender, ep_id) values <foreach collection="users" item="user" separator=","> (#{user.username}, #{user.age}, #{user.gender} <trim prefix="," suffix=")"> <choose> <when test="user.enterpriseId != null and user.enterpriseId != 0"> #{user.enterpriseId} </when> <otherwise> null </otherwise> </choose> </trim> </foreach> </insert> <update id="modifyEnterpriseId"> update user_t set ep_id = #{eid} where id = #{uid} </update> </mapper>
具体语句和表原型大家不用过分关心,一个mybatis的sql配置文件主要有几个细节需要注意:
(1)配置文件中的sql语句与dao接口是如何结合的?
实际上mybatis先扫描配置文件然后将sql语句通过namespace和id反向注册到dao接口中,所以namespace属性表示接口类的全限定名,每一个方法的id则对应接口类中的每一个接口方法。
(2)查询中遇到多个参数的情况怎么办?
如果多个参数都属于一个单一实体,我们可以直接使用实体对象最为参数。例如配置文件中的两条select语句。如果实体的属性名与表的字段明称不一致可以通过resultMap做关联。
如果多个参数不属于单一实体,我们可以在接口方法中通过@Param指定参数的名字然后在语句中使用(参考update方法)。我们应尽量避免在配置文件中使用parameterMap方法和在接口中使用Map对象,因为这样都不利于大型代码的维护。
(3)根据情况的不同动态生成SQL语句也是Mybatis的一大亮点,我很喜欢这个特征(参考insert方法)。不过在实际开发中我不并要求开发人员大量使用(任何一种增加编写难度和提高维护成本的行为都应该被谨慎选择)。
import java.util.List; import java.util.Set; import org.apache.ibatis.annotations.Param; import com.learnhow.springboot.mybatis.entity.User; public interface UserDao { List<User> getAll(); User getOne(long id); int saveUsers(@Param("users") Set<User> users); int modifyEnterpriseId(@Param("uid") long userId, @Param("eid") long enterpriseId); }
四、Mybatis配置文件
DataSourceConfig.java
import javax.sql.DataSource; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; @Configuration @MapperScan(basePackages = "com.learnhow.springboot.mybatis.dao.mimas", // 为指定包中的DAO注入SqlSessionTemplate sqlSessionTemplateRef = "mimasSqlSessionTemplate") // 指定SqlSessionTemplate public class DataSourceConfig { @Bean(name = "mimasDataSource") @ConfigurationProperties(prefix = "spring.datasource.mimas") @Primary public DataSource testDataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "mimasSqlSessionFactory") @Primary public SqlSessionFactory testSqlSessionFactory(@Qualifier("mimasDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); bean.setMapperLocations( new PathMatchingResourcePatternResolver().getResources("classpath:mybatis/mapper/mimas/*.xml")); bean.setTypeAliasesPackage("com.learnhow.springboot.mybatis.entity"); // 指定entity的别名 return bean.getObject(); } @Bean(name = "mimasSqlSessionTemplate") @Primary public SqlSessionTemplate testSqlSessionTemplate( @Qualifier("mimasSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception { return new SqlSessionTemplate(sqlSessionFactory); } }
Springboot的项目都需要配置主数据源,MapperScan表示扫描dao.mimas.*下的所有接口并注入指定的SessionTemplate。下面的三个方法就是产生这个SessionTemplate的过程。
五、事务控制
传统的方法是在service中做事务控制,我们还是沿用这样的开发逻辑。
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import com.learnhow.springboot.mybatis.dao.mimas.UserDao; import com.learnhow.springboot.mybatis.entity.User; @Component public class UserService { @Autowired private UserDao userDao; @Transactional public int saveUsers(Set<User> users) { return userDao.saveUsers(users); } @Transactional public void modifyEnterpriseIdByUserId(Set<User> users) { for(User u : users) { userDao.modifyEnterpriseId(u.getId(), u.getEnterpriseId()); } } }
至此,有关Springboot和mybatis的整合我们已经完成。完整代码由于十分简单我就不提供链接了,有需要帮助的小伙伴可以私信@我。