MyBatis为了方便与Spring Boot集成,专门提供了一个符合其规范的starter项目mybatis-spring-boot-starter。因此,我们只需在pom.xml添加相关依赖即可轻松集成。下面介绍了Spring Boot整合Mybatis的具体步骤以及事务使用(包含解决事务失效的坑),本项目依赖Spring Boot版本为2.X,mybatis为3.X。
1、mysql数据库准备
创建数据库mybatis,并创建sys_user表
CREATE TABLE `sys_user` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`user_name` varchar(50) DEFAULT NULL,`user_password` varchar(50) DEFAULT NULL,`user_email` varchar(50) DEFAULT NULL,`user_info` text,`head_img` blob,`create_time` datetime DEFAULT NULL,PRIMARY KEY (`id`)
)
INSERT INTO `sys_user` VALUES ('1', 'admin', '123456', '1009015337@qq.com', '管理员', null, '2019-06-12 14:44:59');
INSERT INTO `sys_user` VALUES ('2', 'test', '123456', 'test@mybatis.tk', '测试用户', null, '2019-06-11 13:56:03');
2、pom.xml中添加依赖
<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.2</version>
</dependency>
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope>
</dependency>
3、application.properties
#数据源配置
spring.datasource.url=jdbc:mysql://XXXX:3306/mybatis?userUnicode=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=XXXX#mybatis配置
#映射文件的路径,多个配置可以使用英文逗号隔开
mybatis.mapperLocations=classpath:mapper/*.xml
#类型别名包配置,只能指定具体的包,多个配置可以使用英文逗号隔开
mybatis.typeAliasesPackage=com.henry.springboot.model
#日志等级
logging.level.com.henry.springboot.mapper=debug
4、logback.xml日志配置
<configuration><property name="APP_HOME" value="logs" /><!-- ch.qos.logback.core.ConsoleAppender 控制台输出 --><appender name="console" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>[%-5level] %d{HH:mm:ss.SSS} [%thread] %logger - %msg%n</pattern></encoder></appender><!-- 各类基本日志输出 --><appender name="file"class="ch.qos.logback.core.rolling.RollingFileAppender"><File>${APP_HOME}/common/log.log</File><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><FileNamePattern>${APP_HOME}/logs/common/log-%d{yyyy-MM-dd}.%i.log</FileNamePattern><MaxHistory>10000</MaxHistory><TimeBasedFileNamingAndTriggeringPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><MaxFileSize>10GB</MaxFileSize></TimeBasedFileNamingAndTriggeringPolicy></rollingPolicy><layout class="ch.qos.logback.classic.PatternLayout"><pattern>[%-5level] %d{HH:mm:ss.SSS} [%thread] %logger - %msg%n</pattern></layout></appender><!-- 日志级别 --><root><level value="info" /><appender-ref ref="file" /><appender-ref ref="console" /></root></configuration>
至此配置已经基本完成(除mapper.xml文件),在写代码之前先看下项目结构:
5、项目代码
(1)mapper接口及配置
UserMapper类
package com.henry.springboot.mapper;import java.util.List;import org.springframework.transaction.annotation.Transactional;import com.henry.springboot.model.SysUser;public interface UserMapper {/*** 查询全部数据* * @return*/List<SysUser> selectAll();/*** 根据指定条件查询数据* @return*/SysUser selectById(Long id);/*** 插入记录* @param sysUser* @return*/int insert(SysUser sysUser);
}
在src/main/resources中新建mapper文件夹并创建UserMapper.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.henry.springboot.mapper.UserMapper"><select id="selectById" resultType="SysUser">select id, user_name userName,user_password userPassword,user_email userEmail,user_info userInfo,head_img headImg,create_time createTime from sys_user where id = #{id}</select><select id="selectAll" resultType="SysUser">select id, user_name userName,user_password userPassword,user_email userEmail,user_info userInfo,head_img headImg,create_time createTime from sys_user</select><insert id="insert">insert into sys_user(id, user_name, user_password, user_email, user_info, head_img, create_time) values(#{id}, #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType=BLOB},#{createTime, jdbcType=TIMESTAMP})</insert>
</mapper>
(2)服务层代码
服务接口UserService:
package com.henry.springboot.service;import java.util.List;import com.henry.springboot.model.SysUser;public interface UserService {SysUser findById(Long id);List<SysUser> findAll();void insert(SysUser sysUser) throws Exception;
}
服务接口实现类:
package com.henry.springboot.service.impl;import java.util.List;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import com.henry.springboot.mapper.UserMapper;
import com.henry.springboot.model.SysUser;
import com.henry.springboot.service.UserService;@Service
public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper UserMapper;@Overridepublic SysUser findById(Long id) {return UserMapper.selectById(id);}@Overridepublic List<SysUser> findAll() {return UserMapper.selectAll();}@Transactional(rollbackFor = Exception.class)@Overridepublic void insert(SysUser sysUser) throws Exception {int i = UserMapper.insert(sysUser);throw new Exception("发生异常了");}
}
(3)controller代码
UserController类
package com.henry.springboot.controller;import java.util.Date;
import java.util.List;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import com.henry.springboot.model.SysUser;
import com.henry.springboot.service.impl.UserServiceImpl;@RestController
public class UserController {private static final Logger logger = LoggerFactory.getLogger(UserController.class);@Autowiredprivate UserServiceImpl userService;@RequestMapping("users/{id}")SysUser user(@PathVariable("id") Long id) {return userService.findById(id);}@RequestMapping("users")List<SysUser> user() {return userService.findAll();}@RequestMapping("insert")public String insert() {SysUser user = new SysUser();user.setUserName("test");user.setUserPassword("123456");user.setUserEmail("test@qq.com");user.setUserInfo("测试1");user.setHeadImg(new byte[] { 1, 2, 3 });user.setCreateTime(new Date());try {userService.insert(user);} catch (Exception e) {logger.error("", e);}return "success";}
}
(4)model层代码
SysUser类
package com.henry.springboot.model;import java.util.Date;public class SysUser {private Long id;private String userName;private String userPassword;private String userEmail;private String userInfo;private byte[] headImg;private Date createTime;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getUserPassword() {return userPassword;}public void setUserPassword(String userPassword) {this.userPassword = userPassword;}public String getUserEmail() {return userEmail;}public void setUserEmail(String userEmail) {this.userEmail = userEmail;}public String getUserInfo() {return userInfo;}public void setUserInfo(String userInfo) {this.userInfo = userInfo;}public byte[] getHeadImg() {return headImg;}public void setHeadImg(byte[] headImg) {this.headImg = headImg;}public Date getCreateTime() {return createTime;}public void setCreateTime(Date createTime) {this.createTime = createTime;}
}
6、运行
启动Spring Boot
(1)浏览器访问localhost:8080/users获取所有用户
(2)localhost:8080/users/1
7、事务处理
Spring Boot2.X事务处理非常简单,只需要在Service层添加@Transactional注解即可,上面代码中已经添加了。继续在浏览器中输入:localhost:8080/insert
后台:
数据库:
数据中数据依旧是两条,可以看到数据并没有真正插入到数据库中,因为事务遇到异常回滚了。
8、事务处理中的坑
坑1:上面服务层的Transaction后面我们加了(rollbackFor = Exception.class),如果不加会怎么样呢?
我们去掉后重新运行项目后,浏览器继续访问localhost:8080/insert,再看项目后台及数据库:
数据库中记录插入成功了,事务回滚失败!
这是因为Spring的默认事务规则是遇到运行异常(RuntimeException及其子类)和程序错误(Error)才会进行事务回滚,显然throw new Exception("发生异常了");直接抛出不会进行事务回滚,但是可以在@Transactional注解中使用rollbackFor属性明确指定异常。
坑2:mysql的表是有事务安全( 比如:InnoDB)和非事务安全(比如:ISAM、MyISAM)之分的。如果自己的表是MyISAM类型的,那么久改为InnoDB,以支持事务处理。参见文章:https://blog.csdn.net/kaifaxiaoliu/article/details/79990357
最后附上该项目的下载地址:https://download.csdn.net/download/jcy1009015337/11290055,没有积分的私信我~~