Spring Boot整合Mybatis及事務處理

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,沒有積分的私信我~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章