springboot+mybatis+事务

3 篇文章 0 订阅
2 篇文章 0 订阅

1、搭建一个简单的springboot项目,引入相关的依赖及配置。

1.1 application.properties

#pgsql
spring.datasource.url=jdbc:postgresql://localhost:5432/db_name?useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.driver-class-name=org.postgresql.Driver

#如果是mysql,可以换成下面的配置
#spring.datasource.url=jdbc:mysql://localhost:3306/socks?useSSL=false
#spring.datasource.username=username
#spring.datasource.password=password
#spring.datasource.driver-class-name=com.mysql.jdbc.Driver

#mybatis的配置
#mapper文件的位置
mybatis-plus.mapper-locations=classpath*:/mapper/**Mapper.xml
mybatis-plus.type-aliases-package=com.hehe.pojo
mybatis-plus.global-config.id-type=3
mybatis-plus.global-config.field-strategy=2
mybatis-plus.db-column-underline=true
mybatis-plus.refresh-mapper=true
mybatis-plus.logic-delete-value=0
mybatis-plus.logic-not-delete-value=1
#开启驼峰映射
mybatis-plus.configuration.map-underscore-to-camel-case=true
mybatis-plus.cache-enabled=false
#\u5237\u65B0mapper \u8C03\u8BD5\u795E\u5668
mybatis-plus.global-config.refresh-mapper=true

1.2 依赖pom.xml

下面主要的依赖是关于mybatis的和数据源,以及数据库驱动的依赖,具体选择psql还是mysql,自己可以选择。

<?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.hehe</groupId>
	<artifactId>springboot-mybatis</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
	<name>spring-boot-mybatis</name>
	<description>SpringBoot快速整合Mybatis案例</description>

	<!--继承信息 -->
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.0.M4</version>
		<relativePath/>
	</parent>

	<properties>
		<mybatis-plus-boot-starter.version></mybatis-plus-boot-starter.version>
		<druid.version>1.1.2</druid.version>
		<postgresql.version>42.1.4</postgresql.version>
		<mybatis-plus-boot-starter.version>2.2.0</mybatis-plus-boot-starter.version>
		<pagehelper-spring-boot-starter.version>1.2.3</pagehelper-spring-boot-starter.version>
		<slf4j.version>1.7.25</slf4j.version>
		<logback.version>1.2.2</logback.version>
	</properties>

	<!--依赖管理 -->
	<dependencies>
		<dependency> <!--添加Web依赖 -->
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<!--<exclusions>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-tomcat</artifactId>
				</exclusion>
			</exclusions>-->
		</dependency>
		<!--<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jetty</artifactId>
		</dependency>-->

		<!--<dependency>&lt;!&ndash;添加MySQL驱动依赖 &ndash;&gt;
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>-->

		<!--Db begin-->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>${druid.version}</version>
		</dependency>
		<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<version>${postgresql.version}</version>
		</dependency>
		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus-boot-starter</artifactId>
			<version>${mybatis-plus-boot-starter.version}</version>
		</dependency>

		<dependency>
			<groupId>com.github.pagehelper</groupId>
			<artifactId>pagehelper-spring-boot-starter</artifactId>
			<version>${pagehelper-spring-boot-starter.version}</version>
		</dependency>
		<!--Db end-->

		<!--Log begin-->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${slf4j.version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jcl-over-slf4j</artifactId>
			<version>${slf4j.version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jul-to-slf4j</artifactId>
			<version>${slf4j.version}</version>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-access</artifactId>
			<version>${logback.version}</version>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>${logback.version}</version>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-core</artifactId>
			<version>${logback.version}</version>
		</dependency>
		<!--Log end-->

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.16.6</version>
		</dependency>

		<dependency>
			<groupId>joda-time</groupId>
			<artifactId>joda-time</artifactId>
			<version>2.10.1</version>
		</dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.40</version>
        </dependency>


		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jms</artifactId>
			<version>4.3.15.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.apache.activemq</groupId>
			<artifactId>activemq-client</artifactId>
			<version>5.14.5</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>






		<dependency><!--添加Test依赖 -->
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>


	<!--指定远程仓库(含插件)-->
	<repositories>
		<repository>
			<id>spring-snapshots</id>
			<url>http://repo.spring.io/snapshot</url>
			<snapshots><enabled>true</enabled></snapshots>
		</repository>
		<repository>
			<id>spring-milestones</id>
			<url>http://repo.spring.io/milestone</url>
		</repository>
	</repositories>
	<pluginRepositories>
		<pluginRepository>
			<id>spring-snapshots</id>
			<url>http://repo.spring.io/snapshot</url>
		</pluginRepository>
		<pluginRepository>
			<id>spring-milestones</id>
			<url>http://repo.spring.io/milestone</url>
		</pluginRepository>
	</pluginRepositories>

	<!--构建插件 -->
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>

		<resources>
			<resource>
				<directory>src/main/resources</directory>
			</resource>
		</resources>
	</build>

</project>

3、创建事务的配置类(非必须,可以直接应用springboot自带的注解@Transaction)

本文加了一个事务的配置类,如下

package com.hehe.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.Autowired;
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.*;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>全局事务配置</p>
 *
 * @author anna 2019/3/12 18:45
 * @version V1.0
 * @modificationHistory=========================逻辑或功能性重大变更记录
 * @modify by user: {修改人} 2019/3/12
 * @modify by reason:TransactionConfig:{原因}
 */
@Aspect
@Configuration
public class TransactionConfig {

    //事务超时时间
    private static final int TX_METHOD_TIMEOUT=60;

    //com.hehe.service包或其下面的所有子包的任意类的任意方法
    private static final String AOP_POINTCUT_EXPRESSION = "execution (* com.hehe.service..*.*(..))";

    //注入事务管理器
    @Autowired
    private PlatformTransactionManager transactionManager;

    //事务的切面
    @Bean
    public TransactionInterceptor txAdvice() {

        /**
         * 只读事务,不做更新操作
         */
        RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
        readOnlyTx.setReadOnly(true);
        //事务的传播行为required-->[如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务]
        readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

        /**
         * 必须带事务
         * 当前存在事务就使用当前事务,当前不存在事务,就开启一个新的事务
         */
        RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute();
        //检查型异常也回滚--异常回滚
        requiredTx.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
        //传播行为
        requiredTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        //写事务超时
        requiredTx.setTimeout(TX_METHOD_TIMEOUT);

        /***
         * 无事务地执行,挂起任何存在的事务
         */
        RuleBasedTransactionAttribute noTx = new RuleBasedTransactionAttribute();
        noTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);

        /**
         * 方法前缀与事务类型的定义
         */
        Map<String, TransactionAttribute> txMap = new HashMap<>();
        //写事务(一般添加、修改、删除为写事务)
        txMap.put("add*", requiredTx);
        txMap.put("save*", requiredTx);
        txMap.put("insert*", requiredTx);
        txMap.put("update*", requiredTx);
        txMap.put("delete*", requiredTx);
        //只读事务(查询)
        txMap.put("get*", readOnlyTx);
        txMap.put("query*", readOnlyTx);
        txMap.put("find*", readOnlyTx);
        txMap.put("list*", readOnlyTx);
        txMap.put("count*", readOnlyTx);
        txMap.put("exist*", readOnlyTx);
        txMap.put("search*", readOnlyTx);
        //无事务,要求不能在事务中执行的方法
        txMap.put("noTx*", noTx);

        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
        source.setNameMap(txMap);

        TransactionInterceptor txAdvice = new TransactionInterceptor(transactionManager, source);
        return txAdvice;
    }

    @Bean
    public Advisor txAdviceAdvisor() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
        return new DefaultPointcutAdvisor(pointcut, txAdvice());
    }
}

3、service

@Service
public class PassengerHourServiceImpl implements IPassengerHourService {

    private static final Logger log = LoggerFactory.getLogger(PassengerHourServiceImpl.class);

    @Autowired
    private PassengerHourMapper passengerHourMapper;

    @Override
    public void insertPassengerHourList(List<PassengerHour> passengerHourList){
        passengerHourMapper.insertBatch(passengerHourList);
    }
}

package com.hehe.service.impl;

import com.hehe.pojo.PassengerHour;
import com.hehe.service.IPassengerHourService;
import com.hehe.service.ITestTransactionService;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;

/**
 * <p></p>
 *
 * @author anna 2019/3/12 19:28
 * @version V1.0
 * @modificationHistory=========================逻辑或功能性重大变更记录
 * @modify by user: {修改人} 2019/3/12
 * @modify by reason:TestTransactionServiceImpl:{原因}
 */
@Service
public class TestTransactionServiceImpl implements ITestTransactionService {

    private static final Logger log = LoggerFactory.getLogger(TestTransactionServiceImpl.class);
    @Autowired
    private IPassengerHourService passengerHourService;

    @Override
    public void insertPassengerHour(PassengerHour passengerHour,boolean isException) {
        int a=1;
        passengerHourService.insertPassengerHourList(Arrays.asList(passengerHour));
        log.info("has insert,isException=",isException);
        //制造一个异常来导致插入回滚
        if (isException) {
            log.info("has insert,next a/0");
            a=a/0;
        }

    }
}

public interface PassengerHourMapper {
    void insertBatch(@Param("list") List<PassengerHour> passengerHourList);
}
 

PassengerHourMapper.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.hehe.mapper.PassengerHourMapper">

    <sql id="base_columns">
      statistics_time,group_id,group_name,flow_in_num,flow_out_num,flow_net_num,area_size,create_time,update_time
    </sql>

    <!--批量插入-->
    <insert id="insertBatch" parameterType="com.hehe.pojo.PassengerHour">
        insert into tb_passenger_hour_temp (<include refid="base_columns"/>)
        values
        <foreach collection="list" item="item" separator=",">
            (
            #{item.statisticsTime},
            #{item.groupId},
            #{item.groupName},
            #{item.flowInNum},
            #{item.flowOutNum},
            #{item.flowNetNum},
            #{item.areaSize},
            #{item.createTime},
            #{item.updateTime}
            )
        </foreach>
    </insert>
   
</mapper>

controller

package com.hehe.controller;

import com.hehe.pojo.PassengerHour;
import com.hehe.service.ITestTransactionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

/**
 * <p></p>
 *
 * @author anna 2019/3/12 19:34
 * @version V1.0
 * @modificationHistory=========================逻辑或功能性重大变更记录
 * @modify by user: {修改人} 2019/3/12
 * @modify by reason:TestTransactionController:{原因}
 */
@RestController
@RequestMapping("/transaction")
public class TestTransactionController {

    @Autowired
    private ITestTransactionService testTransactionService;

    @GetMapping("/insert")
    public String testInsert(String groupId,boolean isException){
        PassengerHour ph = new PassengerHour();
        ph.setGroupName("test");
        ph.setAreaSize(10);
        ph.setStatisticsTime(LocalDateTime.of(LocalDate.now(), LocalTime.MIN));
        ph.setGroupId(groupId);
        ph.setFlowInNum(1);
        ph.setFlowOutNum(1);
        ph.setFlowNetNum(1);
        ph.setCreateTime(LocalDateTime.now());

        testTransactionService.insertPassengerHour(ph,isException);
        return "success";
    }

}

4、启动并测试

4.1 先测试异常回滚的情况

 

显然从日志可以看出执行了插入语句,那么查询数据库看看是否插入成功

从查询结果来看,插入失败了,说明事务生效了,异常回滚了。

说明一下,具体的数据库表及结构什么的读者可以自己定义一个,这里只是偷懒,应用了之前的一个定义好的表来测试的。

4.2 接下来测试一下正常情况的插入,也就是不抛异常时看看是否能插入成功,主要为了对比更有说服力

显然插入成功了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值