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', '[email protected]', '管理員', null, '2019-06-12 14:44:59');
INSERT INTO `sys_user` VALUES ('2', 'test', '123456', '[email protected]', '測試用戶', 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>
<TimeBasedFileNamingAndTriggeringPolicy
class="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 {
@Autowired
private UserMapper UserMapper;
@Override
public SysUser findById(Long id) {
return UserMapper.selectById(id);
}
@Override
public List<SysUser> findAll() {
return UserMapper.selectAll();
}
@Transactional(rollbackFor = Exception.class)
@Override
public 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);
@Autowired
private 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("[email protected]");
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,沒有積分的私信我~~