框架搭建借鉴了 https://blog.csdn.net/qq_19260029/article/details/78010369?locationNum=5&fps=1
AOP切面事务管理参考,https://blog.csdn.net/qq_26173219/article/details/80837860
以下上干货。
0、项目整体结构
1、 application.properties
#database
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF8&useSSL=true
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#mybatis generally Mapper
mybatis.type-aliases-package=com.hzj.tkdemo.model
mybatis.mapper-locations=classpath:mapper/*.xml
mapper.mappers=com.hzj.tkdemo.common.TkMapper
mapper.identity=MYSQL
#pagehelper
pagehelper.helperDialect=mysql
pagehelper.reasonable=true
pagehelper.supportMethodsArguments=true
pagehelper.params=count=countSql
#log
logging.file=logger.log
#logging.level.*=debug
logging.level.root=debug
2、pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.hzj</groupId>
<artifactId>tkmapper</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>tkmapper</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency> -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency> -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- mybatis starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!-- mybatis pagehelper starter -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.5</version>
</dependency>
<!-- tk.mybatis.mapper 通用mapper starter -->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency> -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3、实体类
3.1 User.java
package com.hzj.tkdemo.model.po;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
/** 用户实体类 */
@Table(name="tb_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY )
private Integer id;
/** 名称 */
@Column(name="name")
private String name;
/** 年龄 */
@Column(name="age")
private Integer age;
/** 身份证编号 */
@Column(name="card_no")
private Integer cardNo;
/** 生日 */
@Column(name="birthday")
private Date birthday;
/** 生日 */
@Column(name="department_id")
private Integer departmentId;
// getter setter method
}
3.2 Department.java
package com.hzj.tkdemo.model.po;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
/** 部门实体类 */
@Table(name="tb_department")
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY )
@Column(name="department_id")
private Integer departmentId;
/** 名称 */
@Column(name="department_name")
private String departmentName;
/** 部门编号*/
@Column(name="department_no")
private String departmentNo;
//getter setter method
}
4、AOP切面事务配置 参考了https://blog.csdn.net/qq_26173219/article/details/80837860
package com.hzj.tkdemo.config;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;
@Aspect
@Configuration
public class TransactionAdviceConfig {
//private static final String AOP_POINTCUT_EXPRESSION = "execution (* com.***.service.*.*(..))";
private static final String AOP_POINTCUT_EXPRESSION = "execution(* *..*Service*.*(..))";
/* @Autowired
private PlatformTransactionManager transactionManager;*/
@Bean
public TransactionInterceptor txAdvice(
@Qualifier("transactionManager")PlatformTransactionManager transactionManager
) {
DefaultTransactionAttribute txAttr_REQUIRED = new DefaultTransactionAttribute();
txAttr_REQUIRED.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
DefaultTransactionAttribute txAttr_REQUIRED_READONLY = new DefaultTransactionAttribute();
txAttr_REQUIRED_READONLY.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
txAttr_REQUIRED_READONLY.setReadOnly(true);
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
source.addTransactionalMethod("add*", txAttr_REQUIRED);
source.addTransactionalMethod("save*", txAttr_REQUIRED);
source.addTransactionalMethod("insert*", txAttr_REQUIRED);
source.addTransactionalMethod("delete*", txAttr_REQUIRED);
source.addTransactionalMethod("remove*", txAttr_REQUIRED);
source.addTransactionalMethod("update*", txAttr_REQUIRED);
source.addTransactionalMethod("change*", txAttr_REQUIRED);
source.addTransactionalMethod("exec*", txAttr_REQUIRED);
source.addTransactionalMethod("set*", txAttr_REQUIRED);
source.addTransactionalMethod("get*", txAttr_REQUIRED_READONLY);
source.addTransactionalMethod("query*", txAttr_REQUIRED_READONLY);
source.addTransactionalMethod("select*", txAttr_REQUIRED_READONLY);
source.addTransactionalMethod("find*", txAttr_REQUIRED_READONLY);
source.addTransactionalMethod("list*", txAttr_REQUIRED_READONLY);
source.addTransactionalMethod("count*", txAttr_REQUIRED_READONLY);
source.addTransactionalMethod("is*", txAttr_REQUIRED_READONLY);
return new TransactionInterceptor(transactionManager, source);
}
@Bean
public Advisor txAdviceAdvisor(@Qualifier("txAdvice")TransactionInterceptor transactionInterceptor) {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
return new DefaultPointcutAdvisor(pointcut, transactionInterceptor );
}
}
5、application启动类
package com.hzj.tkdemo;
import tk.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan(basePackages = { "com.hzj.tkdemo.mapper" }) // 使用 tk.mybatis 的 MapperScan
public class TkmapperApplication {
public static void main(String[] args) {
SpringApplication.run(TkmapperApplication.class, args);
}
}
6、mapper 接口
6.1 TkMapper.java
package com.hzj.tkdemo.common;
import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.MySqlMapper;
public interface TkMapper<T> extends Mapper<T>,MySqlMapper<T>{
}
6.2 UserMapper.java
package com.hzj.tkdemo.mapper;
import org.apache.ibatis.annotations.Param;
import com.hzj.tkdemo.common.TkMapper;
import com.hzj.tkdemo.model.po.User;
/**
* <p>Titile: </p>
* <p>Description: </p>
* @ClassName: UserMapper
* @Author Huangzhijin
* @Date 2018年8月2日
*
*/
public interface UserMapper extends TkMapper<User>{
public User selectByCardNo(@Param("cardNo") int cardNo);
public UserVo selectUserDepartmentByCardNo(User user);
}
7、通用mapper的 junit 测试类
package com.hzj.tkdemo;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
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 com.github.pagehelper.PageHelper;
import com.hzj.tkdemo.mapper.UserMapper;
import com.hzj.tkdemo.model.po.User;
@RunWith(SpringRunner.class)
@SpringBootTest
public class TkmapperApplicationTests {
@Autowired
private UserMapper mapper;
@Test
public void contextLoads() {
}
@Test
public void insertUser() {
User user = new User();
int cardNo = (int)( Math.random()*10_000_000 );
user.setAge(24);
user.setName( cardNo+"用户");
user.setBirthday( new Date() );
user.setCardNo( cardNo );
int rows = mapper.insertSelective( user );
System.out.println( "插入成功:"+ rows );
}
// 批量插入记录
@Test
public void insertMore() {
List<User> recordList = new ArrayList<User>();
for (int i = 0; i < 2; i++) {
User newUser = new User();
int cardNo = (int) (Math.random() * 10000000);
newUser.setAge(26);
newUser.setBirthday(new Date());
newUser.setName(cardNo + "批量插入用户");
newUser.setCardNo(cardNo);
recordList.add(newUser);
}
mapper.insertList(recordList);
System.out.println("批量插入成功");
}
// 根据唯一编号查询用户(通用Mapper查询)
@Test
public void selectByCardNo() {
User paramBean = new User();
paramBean.setCardNo(6647403);
User dbUser = mapper.selectOne(paramBean);
if (dbUser != null) {
System.out.println("数据库用户(通用Mapper查询):" + dbUser.getName());
return;
}
System.out.println("查无此用户");
}
// 根据唯一编号查询用户(XML查询)
@Test
public void selectByCardNoByXml() {
User dbUser = mapper.selectByCardNo(6389248);
if (dbUser != null) {
System.out.println("数据库用户(XML查询):" + dbUser.getName());
return;
}
System.out.println("查无此用户");
}
// 根据年龄查询一组用户
@Test
public void selectByAge() {
User paramBean = new User();
paramBean.setAge(24);
List<User> dbUserList = mapper.select(paramBean);
System.out.println("总共查询数:" + dbUserList.size());
}
// 分页查询用户
@Test
public void selectByPage() {
PageHelper.offsetPage(1, 5);
List<User> dbUserList = mapper.select(null);
for (User item : dbUserList) {
System.out.println("分页用户:" + item.getName());
}
}
// 更新用户信息
@Test
public void updateOneInfo() {
User paramBean = new User();
paramBean.setId(1);
paramBean.setAge(26);
mapper.updateByPrimaryKeySelective(paramBean);
System.out.println("更新成功");
}
}
8、使用*mapper.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.hzj.tkdemo.mapper.UserMapper" >
<resultMap id="userMap" type="com.hzj.tkdemo.model.po.User" >
<id column="id" property="id" jdbcType="INTEGER" />
<result column="name" property="name" jdbcType="VARCHAR" />
<result column="age" property="age" jdbcType="TINYINT" />
<result column="department_id" property="departmentId" jdbcType="INTEGER" />
<result column="card_no" property="cardNo" jdbcType="INTEGER" />
</resultMap>
<resultMap id="departmentMap" type="com.hzj.tkdemo.model.po.Department" >
<id column="department_id" property="departmentId" jdbcType="INTEGER" />
<result column="department_name" property="departmentName" jdbcType="VARCHAR" />
<result column="department_no" property="departmentNo" jdbcType="VARCHAR" />
</resultMap>
<resultMap id="userMap2" type="com.hzj.tkdemo.model.vo.UserVo" >
<association property="user" resultMap="userMap" ></association>
<association property="department" resultMap="departmentMap" ></association>
</resultMap>
<select id="selectByCardNo" resultMap="userMap" parameterType="int" >
select * from tb_user where card_no = #{cardNo} limit 1
</select>
<select id="selectUserDepartmentByCardNo" resultMap="userMap2" parameterType="com.hzj.tkdemo.model.po.User" >
select u.*, d.department_name , d.department_no
from tb_user u
left join tb_department d on u.department_id = d.department_id
where card_no = #{cardNo} limit 1
</select>
</mapper>
9、测试多表关联
@Test
public void testSelect() {
try {
User user = new User();
user.setCardNo( 764690 );
UserVo vo = UserMapper.selectUserDepartmentByCardNo(user);
System.out.println( "111111111");
} catch (Exception e) {
e.printStackTrace();
}
}
10、AOP事务相关代码的测试
10.1 UserService 和 UserServiceImpl
package com.hzj.tkdemo.service;
/**
* <p>Titile: </p>
* <p>Description: </p>
* @className: UserService
* @author Huangzhijin
* @date 2018年8月6日
*
*/
public interface UserService {
void addTest(String cardNo);
}
UserServiceImpl.java
package com.hzj.tkdemo.service.impl;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.github.pagehelper.PageHelper;
import com.hzj.tkdemo.mapper.UserMapper;
import com.hzj.tkdemo.model.po.User;
import com.hzj.tkdemo.service.UserService;
/**
* <p>Titile: </p>
* <p>Description: </p>
* @ClassName: UserServiceImpl
* @Author Huangzhijin
* @Date 2018年8月6日
*
*/
@Service("userService")
public class UserServiceImpl implements UserService{
@Autowired
private UserMapper mapper;
/*
* <p>Title: test</p>
* <p>Description: </p>
* @see com.hzj.tkdemo.service.UserService#test(java.lang.String)
* @author: Huangzhijin
* @date: 2018年8月6日
*/
@Override
public void addTest(String cardNo) {
User user = new User();
int cardNoR = (int)( Math.random()*10_000_000 );
user.setAge(24);
user.setName( "用户1111");
user.setBirthday( new Date() );
user.setCardNo( cardNoR );
int rows = mapper.insertSelective( user );
System.out.println( user.getName()+" id-->" + user.getId() );
//------------------------------------分页查询
PageHelper.offsetPage(1, 5);
List<User> dbUserList = mapper.select(null);
for (User item : dbUserList) {
System.out.println("分页用户:" + item.getName());
}
User paramBean = new User();
paramBean.setId(1);
paramBean.setAge(26);
mapper.updateByPrimaryKeySelective(paramBean);
System.out.println("更新成功");
if ("1".equals(cardNo )) {
throw new RuntimeException("抛出异常看一看");
}
User addUser2 = new User();
int cardNo2 = (int)( Math.random()*10_000_000 );
addUser2.setAge(24);
addUser2.setName( "用户2222");
addUser2.setBirthday( new Date() );
addUser2.setCardNo( cardNo2 );
int rows2 = mapper.insertSelective( addUser2 );
System.out.println( "222222插入成功:"+ rows );
}
}
10.2 junit测试代码
@Test
public void name() {
try {
userServiceImpl.addTest("1");
System.out.println( "111111111");
} catch (Exception e) {
e.printStackTrace();
}
}
10.3 运行效果
2018-08-07 16:00:17.843 DEBUG 11228 --- [ main] org.mybatis.spring.SqlSessionUtils : Creating a new SqlSession
2018-08-07 16:00:17.866 DEBUG 11228 --- [ main] org.mybatis.spring.SqlSessionUtils : Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@49889154]
2018-08-07 16:00:17.905 DEBUG 11228 --- [ main] o.m.s.t.SpringManagedTransaction : JDBC Connection [HikariProxyConnection@1432599360 wrapping com.mysql.jdbc.JDBC4Connection@59328218] will be managed by Spring
2018-08-07 16:00:17.906 DEBUG 11228 --- [ main] c.h.t.mapper.UserMapper.insertSelective : ==> Preparing: INSERT INTO tb_user ( id,name,age,card_no,birthday ) VALUES( ?,?,?,?,? )
2018-08-07 16:00:17.925 DEBUG 11228 --- [ main] c.h.t.mapper.UserMapper.insertSelective : ==> Parameters: null, 用户1111(String), 24(Integer), 6855877(Integer), 2018-08-07 16:00:17.832(Timestamp)
2018-08-07 16:00:17.931 DEBUG 11228 --- [ main] c.h.t.mapper.UserMapper.insertSelective : <== Updates: 1
2018-08-07 16:00:17.935 DEBUG 11228 --- [ main] c.h.t.m.U.insertSelective!selectKey : ==> Executing: SELECT LAST_INSERT_ID()
2018-08-07 16:00:17.946 DEBUG 11228 --- [ main] c.h.t.m.U.insertSelective!selectKey : <== Total: 1
2018-08-07 16:00:17.947 DEBUG 11228 --- [ main] org.mybatis.spring.SqlSessionUtils : Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@49889154]
用户1111 id-->7
2018-08-07 16:00:25.132 DEBUG 11228 --- [ main] org.mybatis.spring.SqlSessionUtils : Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@49889154] from current transaction
2018-08-07 16:00:25.141 DEBUG 11228 --- [ main] SQL_CACHE : Cache Hit Ratio [SQL_CACHE]: 0.0
2018-08-07 16:00:25.240 DEBUG 11228 --- [ main] c.h.t.mapper.UserMapper.select_COUNT : ==> Preparing: SELECT count(0) FROM tb_user
2018-08-07 16:00:25.242 DEBUG 11228 --- [ main] c.h.t.mapper.UserMapper.select_COUNT : ==> Parameters:
2018-08-07 16:00:25.246 DEBUG 11228 --- [ main] c.h.t.mapper.UserMapper.select_COUNT : <== Total: 1
2018-08-07 16:00:25.250 DEBUG 11228 --- [ main] com.hzj.tkdemo.mapper.UserMapper.select : ==> Preparing: SELECT id,name,age,card_no,birthday,department_id FROM tb_user LIMIT ?, ?
2018-08-07 16:00:25.251 DEBUG 11228 --- [ main] com.hzj.tkdemo.mapper.UserMapper.select : ==> Parameters: 1(Integer), 5(Integer)
2018-08-07 16:00:25.259 DEBUG 11228 --- [ main] com.hzj.tkdemo.mapper.UserMapper.select : <== Total: 5
2018-08-07 16:00:25.261 DEBUG 11228 --- [ main] org.mybatis.spring.SqlSessionUtils : Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@49889154]
分页用户:1636388??????
分页用户:7461431??????
分页用户:7421288??
分页用户:8203677用户
分页用户:1用户
2018-08-07 16:00:33.687 DEBUG 11228 --- [l-1 housekeeper] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Pool stats (total=10, active=1, idle=9, waiting=0)
2018-08-07 16:00:39.067 DEBUG 11228 --- [ main] org.mybatis.spring.SqlSessionUtils : Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@49889154] from current transaction
2018-08-07 16:00:39.073 DEBUG 11228 --- [ main] c.h.t.m.U.updateByPrimaryKeySelective : ==> Preparing: UPDATE tb_user SET id = id,age = ? WHERE id = ?
2018-08-07 16:00:39.077 DEBUG 11228 --- [ main] c.h.t.m.U.updateByPrimaryKeySelective : ==> Parameters: 26(Integer), 1(Integer)
2018-08-07 16:00:39.081 DEBUG 11228 --- [ main] c.h.t.m.U.updateByPrimaryKeySelective : <== Updates: 1
2018-08-07 16:00:39.083 DEBUG 11228 --- [ main] org.mybatis.spring.SqlSessionUtils : Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@49889154]
更新成功
2018-08-07 16:01:03.690 DEBUG 11228 --- [l-1 housekeeper] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Pool stats (total=10, active=1, idle=9, waiting=0)
2018-08-07 16:01:05.891 DEBUG 11228 --- [ main] org.mybatis.spring.SqlSessionUtils : Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@49889154]
2018-08-07 16:01:05.892 DEBUG 11228 --- [ main] org.mybatis.spring.SqlSessionUtils : Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@49889154]
2018-08-07 16:01:05.892 DEBUG 11228 --- [ main] o.s.j.d.DataSourceTransactionManager : Initiating transaction rollback
2018-08-07 16:01:05.892 DEBUG 11228 --- [ main] o.s.j.d.DataSourceTransactionManager : Rolling back JDBC transaction on Connection [HikariProxyConnection@1432599360 wrapping com.mysql.jdbc.JDBC4Connection@59328218]
2018-08-07 16:01:05.897 DEBUG 11228 --- [ main] o.s.j.d.DataSourceTransactionManager : Releasing JDBC Connection [HikariProxyConnection@1432599360 wrapping com.mysql.jdbc.JDBC4Connection@59328218] after transaction
2018-08-07 16:01:05.898 DEBUG 11228 --- [ main] o.s.jdbc.datasource.DataSourceUtils : Returning JDBC Connection to DataSource
java.lang.RuntimeException: 抛出异常看一看
at com.hzj.tkdemo.service.impl.UserServiceImpl.addTest(UserServiceImpl.java:66)