Spring事务介绍、Spring集成MyBatis
目录
- 1.Spring的事务
- 1.1 什么是事务?
- 1.2 事务的特性(ACID)
- 1.3 Spring 事务实现方式有哪些?
- 1.4 Spring事务管理接口介绍
- 1.4.1 PlatformTransactionManager:事务管理接口
- 1.4.2 TransactionDefinition:事务属性事务管理器接口
- 1.4.3 TransactionStatus:事务状态
- 2.事务入门案例
- 3.动态代理控制事务
- 4.Spring AOP控制事务
- 5. 基于注解的AOP控制事务
- 5.1 @Transactional 注解使用详解
- 5.2 使用注解控制事务
- 6.Spring整合MyBatis
- 6.1 创建工程
- 6.2 配置数据源
- 6.3 整合MyBatis
- 6.4 测试
1.Spring的事务
1.1 什么是事务?
需要一次执行多条SQL语句时,可以使用事务。通俗一点说,如果这几条SQL语句全部执行成功,则才对数据库进行一次更新,如果有一条SQL语句执行失败,则这几条SQL语句全部不进行执行,即要么都执行,要么都不执行。这个时候需要用到事务。
1.2 事务的特性(ACID)
- 原子性(Atomicity):事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
- 一致性(Consistency):执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的;
- 隔离性(Isolation):并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
- 持久性(Durability):一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
1.3 Spring 事务实现方式有哪些?
Spring事务机制主要包括声明式事务和编程式事务。
- 编程式事务:通过编程的方式管理事务,这种方式带来了很大的灵活性,但很难维护。
- 声明式事务:将事务管理代码从业务方法中分离出来,通过aop进行封装。Spring声明式事务使得我们无需要去处理获得连接、关闭连接、事务提交和回滚等这些操作。使用 @Transactional 注解开启声明式事务。
1.4 Spring事务管理接口介绍
Spring 框架中,事务管理相关最重要的 3 个接口如下:
PlatformTransactionManager
:(平台)事务管理器,Spring 事务策略的核心。TransactionDefinition
:事务定义信息(事务隔离级别、传播行为、超时、只读、回滚规则)。TransactionStatus
:事务运行状态。
1.4.1 PlatformTransactionManager:事务管理接口
Spring 并不直接管理事务,而是提供了多种事务管理器 。
Spring 事务管理器的接口是:PlatformTransactionManager 。
通过这个接口,Spring 为各个平台如:JDBC(DataSourceTransactionManager)、Hibernate(HibernateTransactionManager)、JPA(JpaTransactionManager)等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。
PlatformTransactionManager接口中定义了三个方法:
public interface PlatformTransactionManager { //开启事务 TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; //提交事务void commit(TransactionStatus status) throws TransactionException; //回滚事务void rollback(TransactionStatus status) throws TransactionException;
}
1.4.2 TransactionDefinition:事务属性事务管理器接口
PlatformTransactionManager 通过 getTransaction(TransactionDefinition definition) 方法来得到一个事务,这个方法里面的参数是 TransactionDefinition 类 ,这个类就定义了一些基本的事务属性。什么是事务属性呢?
事务属性可以理解成事务的一些基本配置,描述了事务策略如何应用到方法上。事务属性包含了 5 个方面:
- 隔离级别
- 传播行为
- 回滚规则
- 是否只读
- 事务超时
TransactionDefinition 接口中定义了 5 个方法以及一些表示事务属性的常量比如隔离级别、传播行为等等。
package org.springframework.transaction;import org.springframework.lang.Nullable;public interface TransactionDefinition {int PROPAGATION_REQUIRED = 0;int PROPAGATION_SUPPORTS = 1;int PROPAGATION_MANDATORY = 2;int PROPAGATION_REQUIRES_NEW = 3;int PROPAGATION_NOT_SUPPORTED = 4;int PROPAGATION_NEVER = 5;int PROPAGATION_NESTED = 6;int ISOLATION_DEFAULT = -1;int ISOLATION_READ_UNCOMMITTED = 1;int ISOLATION_READ_COMMITTED = 2;int ISOLATION_REPEATABLE_READ = 4;int ISOLATION_SERIALIZABLE = 8;int TIMEOUT_DEFAULT = -1;// 返回事务的传播行为,默认值为 REQUIRED。int getPropagationBehavior();//返回事务的隔离级别,默认值是 DEFAULTint getIsolationLevel();// 返回事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。int getTimeout();// 返回是否为只读事务,默认值为 falseboolean isReadOnly();@NullableString getName();
}
- 事务隔离级别
-
事务并发时的安全问题
问题 描述 隔离级别 脏读 一个事务读取到另一个事务还未提交的数据 read-commited 不可重复读 一个事务内多次读取一行数据的内容,其结果不一致 repeatable-read 幻读 一个事务内多次读取一张表中的内容,其结果不一致 serialized-read -
Spring事务隔离级别(比数据库事务隔离级别多一个default)由低到高为:
隔离级别 ISOLATION_DEFAULT 这是一个platfromtransactionmanager默认的隔离级别,使用数据库默认的事务隔离级别。 ISOLATION_READ_UNCOMMITTED 这是事务最低的隔离级别,会产生脏读,不可重复读和幻像读。 ISOLATION_READ_COMMITTED 这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。 Oracle数据库默认的隔离级别。 ISOLATION_REPEATABLE_READ 这种事务隔离级别可以防止脏读、不可重复读,但是可能出现幻像读。MySQL数据库默认的隔离级别。 ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别,事务被处理为顺序执行。除了防止脏读、不可重复读外,还避免了幻像读。
- 事务的传播行为
-
什么是事务传播行为?
事务传播行为(propagation behavior)指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行。
例如:methodA事务方法调用methodB事务方法时,methodB是继续在调用者methodA的事务中运行呢,还是为自己开启一个新事务运行,这就是由methodB的事务传播行为决定的。
-
Spring定义了七种传播行为:
事务传播行为类型 说明 PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。 PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。 PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。 PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。 PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。 PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与REQUIRED类似的操作。
- 事务超时
timeout
事务超时时间: 当前事务所需操作的数据被其他事务占用,则等待。- 100:自定义等待时间100(秒)。
- -1:由数据库指定等待时间,默认值。(建议)
- 读写性
readonly
读写性-
true:只读,可提高查询效率,适合查询
-
false:可读可写,适合增删改
-
- 事务回滚规则
这些规则定义了哪些异常会导致事务回滚而哪些不会。
默认情况下,事务只有遇到运行期异常(RuntimeException
的子类)时才会回滚,Error
也会导致事务回滚,但是,在遇到检查型(Checked)异常时不会回滚。
1.4.3 TransactionStatus:事务状态
TransactionStatus接口用来记录事务的状态 该接口定义了一组方法,用来获取或判断事务的相应状态信息。
PlatformTransactionManager.getTransaction(…)
方法返回一个 TransactionStatus 对象。
TransactionStatus 接口内容如下:
public interface TransactionStatus{boolean isNewTransaction(); // 是否是新的事务boolean hasSavepoint(); // 是否有恢复点void setRollbackOnly(); // 设置为只回滚boolean isRollbackOnly(); // 是否为只回滚boolean isCompleted; // 是否已完成
}
2.事务入门案例
通过实现银行转账功能初步认识事务
- applicationContext.xml
创建事物管理器和事物属性bean对象,使用默认id
<!--配置事物管理器--><bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean><!--配置事物属性--><bean class="org.springframework.transaction.support.DefaultTransactionDefinition"><property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/><property name="readOnly" value="false"></property></bean>
- service
业务层实现事务,手动触发一个异常,进行测试
@Service
public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper;@Autowiredprivate TransactionDefinition txDefinition;@Autowiredprivate PlatformTransactionManager txManager;/*** 转账* @param source* @param target* @param money*/@Overridepublic void updateUser(String source, String target, Float money) {// 获取一个事务TransactionStatus txStatus = txManager.getTransaction(txDefinition);try {//扣钱userMapper.updateUserOfSub(source, money);//触发异常,测试事务int a = 6/0;//加钱userMapper.updateUserOfAdd(target, money);//提交事务txManager.commit(txStatus);}catch (Exception e){//回滚事务txManager.rollback(txStatus);e.printStackTrace();}}
}
- 测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")//加载配置文件
public class ServiceTest {@Autowiredprivate UserService userService;/*** 转账业务*/@Testpublic void testUpdate(){userService.updateUser("张三丰","宋远桥",1F);}
}
-
事务回滚:
-
满足执行
我们现在虽然实现了事务控制,但是代码非常的臃肿,我们可以使用动态代理简化代码
3.动态代理控制事务
- factory
创建一个工厂,专门用来给 Service 创建代理对象,如下:
package com.by.factory;import com.by.service.UserService;
import com.by.service.UserServiceImpl;
import org.hamcrest.Factory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** bean工厂*/
@Component
public class BeanFactory {@Autowiredprivate UserService userService;@Autowiredprivate TransactionDefinition txDefinition;@Autowiredprivate PlatformTransactionManager txManager;/*** 获得UserServiceImpl对象** @return*/public UserService getUserService() {return (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),userService.getClass().getInterfaces(),new InvocationHandler() {public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {//开启事务TransactionStatus txStatus = txManager.getTransaction(txDefinition);try {method.invoke(userService, args);//提交事务txManager.commit(txStatus);} catch (Exception e) {//回滚事务txManager.rollback(txStatus);e.printStackTrace();}return null;}});}
}
- applicationContext.xml
<!--配置service代理对象-->
<bean id="proxyService" factory-bean="beanFactory" factory-method="getUserService"></bean>
- service
@Service
public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper; /*** 转账* @param source* @param target* @param money*/@Overridepublic void updateUser(String source, String target, Float money) {userMapper.updateUserOfSub(source, money);int a = 6/0;userMapper.updateUserOfAdd(target, money);}
}
- 测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class ServiceTest {@Autowired@Qualifier("proxyService")//注入代理对象private UserService userService;@Testpublic void testUpdate(){userService.updateUser("张三丰","宋远桥",1F);}
}
- 事务回滚:
动态代理需要手动编写被代理类来指定增强代码,AOP可自动创建代理类从而进一步简化代码
4.Spring AOP控制事务
- 导入schema约束
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd"></beans>
- 配置增强
<!-- 1、增强 --><tx:advice id="txAdvice" transaction-manager="transactionManager"><!--事务属性--><tx:attributes><!-- 指定方法名称:是业务核心方法read-only:是否是只读事务。默认false,不只读。isolation:指定事务的隔离级别。默认值是使用数据库的默认隔离级别。propagation:指定事务的传播行为。timeout:指定超时时间。默认值为:-1。永不超时。rollback-for:用于指定一个异常,当执行产生该异常时,事务回滚。产生其他异常,事务不回滚。省略时任何异常都回滚。--><tx:method name="*" read-only="false" propagation="REQUIRED"/><tx:method name="select*" read-only="true" propagation="SUPPORTS"/><tx:method name="get*" read-only="true" propagation="SUPPORTS"/></tx:attributes></tx:advice>
- 配置切点
<aop:config><!--2、切点--><aop:pointcut expression="execution(* com.by.service.*.*(..))" id="pointcut"/></aop:config>
- 配置切面
<aop:config><!--3、切面--><aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"></aop:advisor></aop:config>
- 测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")//加载配置文件
public class ServiceTest {@Autowiredprivate UserService userService;/*** 转账业务*/@Testpublic void testUpdate(){userService.updateUser("张三丰","宋远桥",1F);}
}
-
事务回滚:
5. 基于注解的AOP控制事务
5.1 @Transactional 注解使用详解
- @Transactional 的作用范围
方法:推荐将注解使用于方法上,不过需要注意的是:该注解只能应用到 public 方法上,否则不生效。
类:如果这个注解使用在类上的话,表明该注解对该类中所有的 public 方法都生效。
接口:不推荐在接口上使用。
- @Transactional 的常用配置参数
@Transactional注解源码如下,里面包含了基本事务属性的配置:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {@AliasFor("transactionManager")String value() default "";@AliasFor("value")String transactionManager() default "";Propagation propagation() default Propagation.REQUIRED;Isolation isolation() default Isolation.DEFAULT;int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;boolean readOnly() default false;Class<? extends Throwable>[] rollbackFor() default {};String[] rollbackForClassName() default {};Class<? extends Throwable>[] noRollbackFor() default {};String[] noRollbackForClassName() default {};}
- @Transactional 的常用配置参数总结(只列出了 5 比较常用的):
属性名 | 说明 |
---|---|
propagation | 事务的传播行为,默认值为 REQUIRED,可选的值在上面介绍过 |
isolation | 事务的隔离级别,默认值采用 DEFAULT,可选的值在上面介绍过 |
timeout | 事务的超时时间,默认值为-1(不会超时)。如果超过该时间限制但事务还没有完成,则自动回滚事务。 |
readOnly | 指定事务是否为只读事务,默认值为 false。 |
rollbackFor | 用于指定能够触发事务回滚的异常类型,并且可以指定多个异常类型。 |
- @Transactional 事务注解原理
@Transactional 的工作机制是基于 AOP 实现的,AOP 又是使用动态代理实现的。如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理,如果目标对象没有实现了接口,会使用 CGLIB 动态代理。
5.2 使用注解控制事务
- applicationContext.xml
<!-- 开启spring对注解事务的支持 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
- service
@Service
@Transactional(readOnly=true,propagation= Propagation.SUPPORTS)
public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper;/*** 转账* @param source* @param target* @param money*/@Override@Transactional(readOnly=false,propagation=Propagation.REQUIRED)public void updateUser(String source, String target, Float money) {userMapper.updateUserOfSub(source, money);int a = 6/0;userMapper.updateUserOfAdd(target, money);}
}
- 测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")//加载配置文件
public class ServiceTest {@Autowiredprivate UserService userService;/*** 转账业务*/@Testpublic void testUpdate(){userService.updateUser("张三丰","宋远桥",1F);}
}
- 事务回滚:
6.Spring整合MyBatis
6.1 创建工程
- 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.by</groupId><artifactId>Spring_MyBatis</artifactId><version>1.0-SNAPSHOT</version><properties><!-- 项目源码及编译输出的编码 --><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><!-- 项目编译JDK版本 --><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><dependencies><!-- Spring常用依赖 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.1.8.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.1.8.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>5.1.8.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.1.8.RELEASE</version></dependency><!-- MySql --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency><!--连接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.0</version></dependency><!--mybatis--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.3</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.0.3</version></dependency><!--日志--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.26</version></dependency><!--junit--><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.1.8.RELEASE</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.32</version></dependency></dependencies><build><resources><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource><resource><directory>src/main/resources</directory></resource></resources></build>
</project>
- log4j.properties:配置日志输出文件
log4j.rootLogger=DEBUG,A1log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=[%t] [%c]-[%p] %m%n
- applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.by"></context:component-scan>
</beans>
6.2 配置数据源
- db.properties:配置数据库连接信息
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring?useUnicode=true&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=1111
- applicationContext.xml:配置数据源
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--加载配置文件--><context:property-placeholder location="classpath:db.properties" /><!-- 配置数据源 --><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"destroy-method="close"><property name="driverClassName" value="${jdbc.driverClass}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></bean>
</beans>
6.3 整合MyBatis
- applicationContext.xml
<!--会话工厂-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource"></property><property name="typeAliasesPackage" value="com.by.pojo"></property>
</bean><!--扫描basePackage所指定的包下的所有接口,生成代理类并交给spring管理-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><!--mapper所在的包--><property name="basePackage" value="com.by.mapper"></property><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
6.4 测试
- 创建表
CREATE TABLE `t_user` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(255) DEFAULT NULL,`money` float DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8;
- pojo
package com.by.pojo;@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class User {private Integer id;private String name;private Float money;}
- mapper
public interface UserMapper {public void addUser(User user);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.by.mapper.UserMapper"><insert id="addUser" parameterType="User">insert into t_user(name,money) values(#{name},#{money})</insert>
</mapper>
- service
@Service
public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper;@Overridepublic void addUser(User user) {userMapper.addUser(user);}
}
- junit
package com.by.test;import com.by.pojo.User;
import com.by.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")//加载配置文件
public class ServiceTest {@Autowiredprivate UserService userService;@Testpublic void testAdd(){userService.addUser(new User("张三丰",4000F));userService.addUser(new User("宋远桥",2000F));}
}
相关文章:

Spring事务介绍、Spring集成MyBatis
目录 1.Spring的事务1.1 什么是事务?1.2 事务的特性(ACID)1.3 Spring 事务实现方式有哪些?1.4 Spring事务管理接口介绍1.4.1 PlatformTransactionManager:事务管理接口1.4.2 TransactionDefinition:事务属性事务管理器接口1.4.3 T…...

使用GPG来解密和加密文件详解
文章目录 使用私钥解密文件示例步骤 注意事项加密文件前提条件导入公钥加密文件输出加密文件示例步骤注意事项邮箱不是必须的情况1:有多个公钥情况2:只有一个公钥示例步骤示例1:指定公钥ID或邮箱地址示例2:密钥环中只有一个相关的…...

【Flutter】基础教程:从安装到发布
Flutter 是一种流行的开源移动应用开发框架,由 Google 开发,可用于构建高性能、跨平台的移动应用。本教程将带领你从安装 Flutter 开发环境开始,一步步完成第一个程序,并介绍如何将应用发布到各个平台上。 跨端原理的关键点包括&a…...

51单片机学习记录———定时器
文章目录 前言一、定时器介绍二、STC89C52定时器资源三、定时器框图四、定时器模式五、定时器相关寄存器六、定时器练习 前言 一个学习嵌入式的小白~ 有问题评论区或私信指出~ 提示:以下是本篇文章正文内容,下面案例可供参考 一、定时器介绍 定时器介…...

C# 热插拔---插件开发
热插拔是以多态,文件监控,反射为基础的。所以用到的是FileSystemWatcher类和 Assembly 类,主要原理就是动态加载dll文件,而要监控dll文件,最好的就是用FileSystemWatcher类,它可以实时监控指定路径下的文件…...

hive优化之逻辑类似or逻辑重复
今天拿到一个二次开发的需求,只是增加一个业务类型,开发起来倒是也蛮轻松。 但是,对自己的要求不难这么低,否则可替代性也太高了。 除了完成自己的那部分开发,当然展现自己实力的,可以是优化。 1&#x…...

ES6+Vue
ES6Vue ES6语法 VUE基于是ES6的,所以在使用Vue之前我们需要先了解一下ES6的语法。 1.什么是ECMAScript6 ECMAScript是浏览器脚本语言的规范,基于javascript来制定的。为什么会出现这个规范呢? 1.1.JS发展史 1995年,网景工…...

如何将重量传感器 HX711 与 Arduino 一起使用
How to use a Weight Sensor / Load Cell HX711 with an Arduino 原文 OVERVIEW We’ve all used a scale to determine the weight of something at some point in our lives. Using a Load Cell or Weight sensor you can add this capability to your Arduino projects.…...

HarmonyOS Next开发学习手册——应用启动框架AppStartup
概述 AppStartup提供了一种简单高效的初始化组件的方式,开发者可以使用AppStartup来显示的设置组件的初始化顺序以及之间的依赖关系,支持异步初始化组件加速应用的启动时间。开发者需要分别为待初始化的组件实现AppStartup提供的 StartupTask 接口&…...

如何在Springboot中添加事务执行?(以MySQL为例)
目录 1. 添加依赖 2. 配置数据库连接 3. 启用事务管理 4. 创建实体类和存储库 5. 创建服务类并使用Transactional注解 6. 编写测试用例 7. 运行应用程序 在Springboot中开启数据库的事务的应用开发过程中非常重要的业务,以下是一个使用MySQL数据库࿰…...

优化MySQL并发事务:如何避免更新丢失问题?
背景描述 现在有两个事务,事务A和事务B,他们都需要修改同一行数据,这行数据原始值为100,事务A的操作是数据增加100,事务B的操作也是增加100,预期的最终结果是300,现在如何保证最终的数据是300的…...

物联网设备管理系统设计
一、引言 物联网设备管理系统设计旨在通过物联网技术实现对设备的全面监控、控制和管理,以提高设备的运行效率、降低运维成本,并确保数据的安全性和完整性。本设计将结合当前物联网技术的发展趋势和实际应用需求,提出一个清晰、可扩展的物联网…...

python之Bible快速检索器
内容将会持续更新,有错误的地方欢迎指正,谢谢! python之Bible快速检索器 TechX 坚持将创新的科技带给世界! 拥有更好的学习体验 —— 不断努力,不断进步,不断探索 TechX —— 心探索、心进取! 助力快…...

微服务-网关
网关:就是网络的关口,负责请求的路由、转发、身份校验 在SpringCloud中网关的实现包括两种: 快速入门 引入依赖 路由属性 网关路由对应的Java类型是RouteDefinition,其中常见的属性有: id:路由唯一标示ur…...

OpenAI项目爆改GLM——以基于llama_index的pdf阅读助手
最近在做大模型agent构建,看了许多不错的开源项目,但是clone下来就是一整个不能用,因为github上开源的项目基本都是基于openai做的。而如果想要转成国内大模型backbone,需要修改的地方挺多的。 现在以一个简单的pdf reader agent…...

如何在Java中处理ParseException异常?
如何在Java中处理ParseException异常? 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿! 在Java编程中,ParseException异常是开发者在处理…...

Java中如何解决BadPaddingException异常?
Java中如何解决BadPaddingException异常? 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿! 在Java编程中,BadPaddingException异常是一个…...

数电大作业-四输入表决器
(PCB和multisim仿真画的有很大问题,没有VCC输入和GND,没学过直接裸画的,之后会好好看视频学习) 应用背景: 四个评委,三个及以上评委同时按下通过按钮时,选手才能通过。否则不通过。…...

ONLYOFFICE 桌面编辑器 8.1重磅来袭:全新功能提升您的办公效率
文章目录 前言ONLYOFFICE 桌面编辑器8.1一、PDF编辑:告别“头痛”时刻二、幻灯片版式:秒变“设计大师”三、无缝切换:办公界的“快速通道”四、语言支持:全球通吃的“翻译官”五、 隐藏“连接到云”板块:摆脱“云”的束…...

网络协议安全:TCP/IP协议栈的安全问题和解决方案
「作者简介」:北京冬奥会网络安全中国代表队,CSDN Top100,就职奇安信多年,以实战工作为基础对安全知识体系进行总结与归纳,著作适用于快速入门的 《网络安全自学教程》,内容涵盖Web安全、系统安全等12个知识域的一百多个知识点,持续更新。 这一章节我们需要知道TCP/IP每…...

VERYCLOUD睿鸿股份亮相亚马逊云科技中国峰会2024
5月30日,为期两天的亚马逊云科技中国峰会在上海世博中心圆满落幕。 多位大咖现场分享,生成式AI时代的数据战略,企业级AI应用,最新技术、产品重磅发布,创新行业解决方案 …… 作为亚马逊云科技的生态合作伙伴&#x…...

2-15 基于matlab的蚁群,模拟退火,遗传,神经网络,禁忌搜索等智能优化算法对TSP问题
基于matlab的蚁群,模拟退火,遗传,神经网络,禁忌搜索等智能优化算法对TSP问题。五种优化算法对多个城市路径进行规划,通过优化速度、距离可比较五种方法的优劣。程序已调通,可直接运行。 2-15 蚁群优化算法 …...

kylinos 国产操作系统离线安装firefox 麒麟操作系统安装新版本firefox
1. 火狐地址: 下载 Firefox 浏览器,这里有简体中文及其他 90 多种语言版本供您选择 2. 选择: 3. 下载完之后,上传到离线机器 4. 解压缩: tar -xvjf firefox-127.0.1.tar.bz2 5. 去点击解压后的文件夹,找…...

Python 类对象
Python 类对象 经典迭代器 可迭代对象的定义: 使用内置的iter可以获取迭代器的对象。如果对象实现了能返回迭代器的__iter__方法,那么对象就是可迭代的。序列都可以迭代。实现了__getitem__方法,而且接受从0开始的索引,这种对象也…...

pytest unittest temp path单元测试创建临时文件
参考了这个:Test Files Creating a Temporal Directory in Python Unittests | Simple IT 🤘 Rocks 并使用pathlib做了优化: import tempfile import unittest from pathlib import Pathclass TestExample(unittest.TestCase):def test_exa…...

在线样机生成器,制作精美的电脑手机壁纸图片展示
在线样机生成器,可以制作精美的电脑手机壁纸图片展示。在线样机生成器支持不同的模型如浏览器、手机、笔记本电脑、手表等结合使用,帮助用户快速生成样机展示图片。下面小编就来和大家分享一款免费的在线样机生成器-壁纸样机生成器。 壁纸样机生成器是一…...

FreeRTOS实时操作系统
1.认识实施操作系统 1.1 裸机和实时操作系统 裸机: 早期嵌入式开发没有嵌入式操作系统的概念,直接操作裸机,在裸机上写程序,比如用51单片机基本就没有操作系统的概念。 通常把程序设计为前后台系统,主要分为两部分&a…...

C/S、B/S架构(详解)
一、CS、BS架构定义 CS架构(Client-Server Architecture)是一种分布式计算模型,其中客户端和服务器之间通过网络进行通信。在这种架构中,客户端负责向服务器发送请求,并接收服务器返回的响应。服务器则负责处理客户端的…...

代码随想录算法训练营第六十五天|KM99. 岛屿数量——深搜、KM99. 岛屿数量——广搜、KM100. 岛屿的最大面积
代码随想录算法训练营第六十五天 KM99. 岛屿数量——深搜 题目链接:KM99. 岛屿数量 使用递归深度搜索,将每次遇到的岛屿上下左右记录为已经到过,如果遇到没到过的说明它上下左右不是之间遍历过的岛屿,结果计数1。最后统计计数即…...

Lua 面向对象编程
Lua 面向对象编程 Lua 是一种轻量级的编程语言,通常用于嵌入应用程序中,提供灵活的扩展和定制功能。尽管 Lua 本身是一种过程式语言,但它提供了强大的元机制,允许开发者实现面向对象的编程范式。本文将探讨 Lua 中的面向对象编程(OOP)概念、实现方式以及最佳实践。 面向…...