第五篇:SpringBoot整合Mybatis
前言
前面两篇文章和读者聊了Spring Boot中最简单的数据持久化方案JdbcTemplate,JdbcTemplate虽然简单,但是用的并不多,因为它没有MyBatis方便,在Spring+SpringMVC中整合MyBatis步骤还是有点复杂的,要配置多个Bean,Spring Boot中对此做了进一步的简化,使MyBatis基本上可以做到开箱即用,本文就来看看在Spring Boot中MyBatis要如何使用。
工程创建
pom依赖
<!-- web支持: 1、web mvc; 2、restful; 3、jackjson支持; 4、aop ... --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- servlet依赖 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> </dependency> <!-- tomcat 的支持. --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <scope>provided</scope> </dependency> <!-- FreeeMarker模板引擎所需依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> <!-- springboot测试 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <!-- mysql数据库驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- jdbc依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!-- spring-boot mybatis依赖:注意:不要使用1.0.0版本,因为还不支持拦截器插件,我这里 1.1.1 目前可用 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.1.1</version> </dependency> <!-- 分页插件 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>4.1.0</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency>
实体类
public class User { private Long id; private String username; private String address; // 省略get set }
application.yml
spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC username: root password: 123456 type: com.alibaba.druid.pool.DruidDataSource
注解方式
mapper接口
@Mapper public interface UserMapper1 { @Select("select * from user") List<User> getAllUsers(); @Results({ @Result(property = "id", column = "id"), @Result(property = "username", column = "u"), @Result(property = "address", column = "a") }) @Select("select id as id, username as u, address as a from user where id = #{id}") User getUserById(Long id); @Select("select * from user where username like CONCAT(‘%‘,#{name},‘%‘)") List<User> getUsersByName(String name); @Insert({"insert into user(username, address) values(#{username},#{address})"}) @SelectKey(statement = "", keyProperty = "", before = false, resultType = Integer.class) Integer addUser(User user); @Update("update user set username = #{username}, address = #{address} where id = #{id}") Integer updateUserById(User user); @Delete("delete from user where id = #{id}") Integer deleteUserById(Integer id); }
UserService
@Service public class UserService1 { @Autowired private UserMapper1 userMapper1; public List<User> getAllUser(){ return userMapper1.getAllUsers(); } public List<User> getUsersByName(String name){ return userMapper1.getUsersByName(name); } public User getUserById(Long id){ return userMapper1.getUserById(id); } public Integer addUser(User user){ return userMapper1.addUser(user); } public Integer updateUserById(User user){ return userMapper1.updateUserById(user); } public Integer deleteUserById(Integer id){ return userMapper1.deleteUserById(id); } }
xml方式
mapper接口
import java.util.List; @Mapper public interface UserMapper { List<User> getAllUser(); Integer addUser(User user); Integer updateUserById(User user); Integer deleteUserById(Integer id); }
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.demo.dao.UserMapper"> <select id="getAllUser" resultType="com.demo.entity.User"> select * from user; </select> <insert id="addUser" parameterType="com.demo.entity.User"> insert into user (username,address) values (#{username},#{address}); </insert> <update id="updateUserById" parameterType="com.demo.entity.User"> update user set username=#{username},address=#{address} where id=#{id} </update> <delete id="deleteUserById"> delete from user where id=#{id} </delete> </mapper>
修改pom和application.yml
整体测试
package com.demo; import com.demo.entity.User; import com.demo.service.UserService1; import com.demo.service.UserService2; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.List; @RunWith(SpringRunner.class) @SpringBootTest public class MybatisTest { @Autowired private UserService1 userService1; @Autowired private UserService2 userService2; //mybatis注解测试 @Test public void addUser(){ User user = new User(); user.setUsername("2神经薛之谦2"); user.setAddress("上海"); int result = userService1.addUser(user); System.out.println(result==1 ? "Success":"fail"); } @Test public void updateUser(){ User user = new User(); user.setId(3L); user.setUsername("岳云鹏"); user.setAddress("北京"); int result = userService1.updateUserById(user); System.out.println(result==1 ? "Success":"fail"); } @Test public void delUser(){ int result = userService1.deleteUserById(2); System.out.println(result==1 ? "Success":"fail"); } @Test public void getUserById(){ User user = userService1.getUserById(1L); System.out.println(user.toString()); } @Test public void getUserByName(){ List<User> users = userService1.getUsersByName("薛"); for (User user : users){ System.out.println(user.toString()); } } @Test public void getAllUsers(){ List<User> users = userService1.getAllUser(); for (User user : users){ System.out.println(user.toString()); } } //xml测试 @Test public void addUserXml(){ User user = new User(); user.setUsername("张佳宁"); user.setAddress("北京"); int result = userService2.addUser(user); System.out.println(result==1 ? "Success":"fail"); } @Test public void updateUserXml(){ User user = new User(); user.setId(5L); user.setUsername("薛之谦"); user.setAddress("北京"); int result = userService2.updateUserById(user); System.out.println(result==1 ? "Success":"fail"); } @Test public void delUserXml(){ int result = userService2.deleteUserById(6); System.out.println(result==1 ? "Success":"fail"); } @Test public void getAllUsersXml(){ List<User> users = userService2.getAllUser(); for (User user : users){ System.out.println(user.toString()); } } }
原理分析
在SSM整合中,开发者需要自己提供两个Bean,一个SqlSessionFactoryBean,还有一个是MapperScannerConfigurer,在Spring Boot中,这两个东西虽然不用开发者自己提供了,但是并不意味着这两个Bean不需要了,在org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
类中,我们可以看到Spring Boot提供了这两个Bean,部分源码如下:
@org.springframework.context.annotation.Configuration @ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class }) @ConditionalOnSingleCandidate(DataSource.class) @EnableConfigurationProperties(MybatisProperties.class) @AutoConfigureAfter(DataSourceAutoConfiguration.class) public class MybatisAutoConfiguration implements InitializingBean { @Bean @ConditionalOnMissingBean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { SqlSessionFactoryBean factory = new SqlSessionFactoryBean(); factory.setDataSource(dataSource); return factory.getObject(); } @Bean @ConditionalOnMissingBean public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { ExecutorType executorType = this.properties.getExecutorType(); if (executorType != null) { return new SqlSessionTemplate(sqlSessionFactory, executorType); } else { return new SqlSessionTemplate(sqlSessionFactory); } } @org.springframework.context.annotation.Configuration @Import({ AutoConfiguredMapperScannerRegistrar.class }) @ConditionalOnMissingBean(MapperFactoryBean.class) public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean { @Override public void afterPropertiesSet() { logger.debug("No {} found.", MapperFactoryBean.class.getName()); } } }
从类上的注解可以看出,当当前类路径下存在SqlSessionFactory、 SqlSessionFactoryBean以及DataSource时,这里的配置才会生效,SqlSessionFactory和SqlTemplate都被提供了。