分享自己敲代码&写笔记时候听的歌
这首是 '命运石之门' 的op,这种节奏向的歌很适合码字,前提是手速能跟上,当然错别字什么的,无所谓的啦!
什么啦,才不是心思都在歌上,我有用心学习的,认真脸!
随便把歌曲的网易云的引用代码附上,想要拿去即可。
<iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=330 height=86 src="//music.163.com/outchain/player?type=2&id=26584163&auto=1&height=66"></iframe>
Spring事务
介绍
首先事务是数据库中的概念,在DAO层。但是要使用事务管理具体的业务,为了方便一般吧事务提高到业务层即service层。
-
- Spring事务管理的API
- 1.1 事务管理器是PlatformTransactionManager接口对象。主要用于事务的提交,回滚,及获取事务的状态信息。
PlatformTransactionManager:的两个实现类
DataSourceTransactionManager:使用JDBC或MyBatis进行持久化数据时使用
HibernaTransactionManager:使用Hibernate进行持久化数据时使用 - 1.2 Spring的回滚方式
Srping事务的默认回滚方式是:发生运行时异常回滚,发生受查异常时提交。 - 1.3 事务定义接口PlatformTransactionManager定义了事务描述的三大常量:事务隔离级别,事务传播行为,事务牧人超时时限,以及对他们的操作。
所谓事务传播行为是指,处于不同事物中的方法在相互调用时,执行期间事物的维护情况。如,A事物中的方法doSome()调用B事务中的方法doOther(),在调用时执行期间事务的维护情况,成为事务的传播行为。
-
- 环境搭建
-
- 使用AspectJ的AOP配置管理事务(重)
-
- 使用事务注解管理事务
环境搭建
maven依赖添加
spring核心包,spring-aop包,spring-context包,spring-orm包,aspectj包
上述之前就用过不在赘述
下面是添加的新的依赖
spring-jdbc,spring-tx,c3p0,mysql驱动
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!--spring事务-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!--数据库连接池3cp0-->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
需求
实现银行和基金会的小业务,向基金会买基金,银行会扣钱,这两个操作应该是一个事务
数据库表设计
account:银行表
create table account
(
aid int(5) auto_increment
primary key,
aname varchar(255) null,
balance double null
);
fund:基金表
create table fund
(
fid int(5) auto_increment
primary key,
fname varchar(255) null,
count int(100) null
);
DAO层设计
两个接口两个实现类AccountDao和FundDao
AccountDaoImpl
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
// 开银行账户
public void inserAccount(String aname, double money) {
String sql = "insert into account(aname, balance) values(?,?)";
this.getJdbcTemplate().update(sql, aname, money);
}
// 更新银行账户
public void updateAccount(String aname, double money) {
String sql = "update account set balance=balance-? where aname=?";
this.getJdbcTemplate().update(sql, money, aname);
}
}
FundDaoImpl
public class FundDaoImpl extends JdbcDaoSupport implements FundDao {
// 开基金账户
public void insertFound(String fname, int amount) {
String sql = "insert into fund(fname, count) values(?,?)";
this.getJdbcTemplate().update(sql, fname, amount);
}
// 买基金
public void updateFound(String fname, int amount) {
String sql = "update fund set count=count+? where fname=?";
this.getJdbcTemplate().update(sql, amount, fname);
}
}
业务层设计
一个接口一个实现类FundService
public class FundServiceImpl implements FundService {
private AccountDao accountDaoImpl;
private FundDao fundDaoImpl;
public AccountDao getAccountDaoImpl() {
return accountDaoImpl;
}
public FundDao getFundDaoImpl() {
return fundDaoImpl;
}
public void setAccountDaoImpl(AccountDao accountDaoImpl) {
this.accountDaoImpl = accountDaoImpl;
}
public void setFundDaoImpl(FundDao fundDaoImpl) {
this.fundDaoImpl = fundDaoImpl;
}
// 开银行账户
public void openAccount(String aname, double money) {
accountDaoImpl.inserAccount(aname, money);
}
// 开基金账户
public void openFound(String fname, int amount) {
fundDaoImpl.insertFound(fname, amount);
}
// 买基金
public void buyFund(String aname, double money, String fname, int amount) throws FundException {
accountDaoImpl.updateAccount(aname, money);
fundDaoImpl.updateFound(fname, amount);
}
}
pojo设计
这个也没啥好设计的,根据表的字段名创建实体类就是了,略!
jdbc.properties文件
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/java?serverTimezone=UTC
jdbc.username=root
jdbc.password=123
异常类设计
public class FundException extends Exception {
public FundException() {
}
public FundException(String message) {
super(message);
}
}
AOP通过配置XML实现事务
添加xml约束
因为配置需要使用tx标签,context标签,aop标签,所以需要添加约束
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
1. 加载jdbc属性文件
<context:property-placeholder location="jdbc.properties"/>
2. 注册c3p0数据源
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
将我们之前加载jdbc的属性文件,使用property注入c3p0
3. 注册Dao层
<bean id="accountDao" class="top.byfree.dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="fundDao" class="top.byfree.dao.impl.FundDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
将之前注册的c3p0数据源注入Dao层的实现类,因为Dao层的实现类继承了JdbcDaoSupport所以数据源可以直接注入
4. 注册Service层
<bean id="fundService" class="top.byfree.service.impl.FundServiceImpl">
<property name="accountDaoImpl" ref="accountDao"/>
<property name="fundDaoImpl" ref="fundDao"/>
</bean>
因为fundService的实现类有Dao层的引用属性和set方法,所以这里可以将Dao层对象直接注入
5. 注册事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
以上5步不论是使用xml配置事务还是使用注解开发事务,都必须有。
也就是说接下来的步骤才是真正开始配置事务
6. 注册事务通知
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--连接点方法的事务属性配置-->
<tx:method name="open*" isolation="DEFAULT" propagation="REQUIRED"/>
<tx:method name="buy*" isolation="DEFAULT" propagation="REQUIRED" rollback-for="FundException"/>
</tx:attributes>
</tx:advice>
其他的参数以后有机会细究,这里最重要的参数就是rollback-for设置回滚的异常,意思就是遇到什么异常不进行提交而是回滚,这里写的是我们声明的异常
no-rollback-for这个属性的意思也很好理解,就是遇到什么异常不回滚
7. AOP配置
<aop:config>
<aop:pointcut id="fundPc" expression="execution(* *..service.*.buyFund(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="fundPc"/>
</aop:config>
就是正常的匹配切入点什么的,正常的aop配置,不过这里配置的是一个顾问而不是一个通知
aop:advisor顾问标签通过advice-ref引用一个通知
编写测试类测试
public class test {
private FundService service;
@Before
public void Before() {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
service = ac.getBean("fundService", FundService.class);
}
// 开账户
@Test
public void openAccount () {
service.openAccount("工商银行", 10000);
}
@Test
public void openFund () {
service.openFound("byFree基金", 2000);
}
@Test
public void buyFund () throws FundException {
service.buyFund("工商银行",2000, "byFree基金", 2000);
}
}
手动抛出异常测试
为了测试效果,手动在buyFund方法中两个dao操作的中间抛出一个异常,看是否回滚
public void buyFund(String aname, double money, String fname, int amount) throws FundException {
accountDaoImpl.updateAccount(aname, money);
if (1==1) {
throw new FundException("购买基金异常!");
}
fundDaoImpl.updateFound(fname, amount);
}
使用注解开发事务
注解开发就会简单很多
不需要在进行配置事务通知和aop配置
也就是说之前的配置只需要做到第5步
配置注解驱动
<tx:annotation-driven transaction-manager="transactionManager"/>
将之前的678步换成这一句即可
使用@Transactional注解
@Transactional(rollbackFor = FundException.class)
public void buyFund(String aname, double money, String fname, int amount) throws FundException {
accountDaoImpl.updateAccount(aname, money);
if (1==1) {
throw new FundException("购买基金异常!");
}
fundDaoImpl.updateFound(fname, amount);
}
在业务层的buyFund方法上是用@Transactional注解,这个注解的传值,可以是之前tx:method标签中的那些属性,注意的是rollbackFor的值需要是一个Class对象