spring---事務管理練習
阿新 • • 發佈:2020-12-19
所要完成的功能—轉賬(這裡使用的是maven工程)
案例:甲乙兩個人轉錢,正常情況下:甲輸入乙的賬號,輸入金額,然後甲的賬戶扣除相應的錢,乙的賬戶扣除相應的錢;
但是就是有特殊情況,甲在輸入賬號的時候輸錯了,就會發生一個情況,甲的錢扣掉了,但是乙沒有收到錢,肯定就會出現問題;這就是事務相關的問題:
解決辦法:但雙方進行轉賬時其中一方發生異常,及時進行回滾,等待資料正常時在進行提交
一、建立進行轉賬的賬號資料庫
CREATE TABLE userinfo
(
id
int(11) NOT NULL AUTO_INCREMENT,
username
varchar(255) DEFAULT NULL,
birthday
datetime DEFAULT NULL,sex
varchar(1) DEFAULT NULL,address
varchar(255) DEFAULT NULL,money
int(255) DEFAULT NULL,PRIMARY KEY (
id
)) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
插入資料:BEGIN;
INSERT INTO userinfo
VALUES (1, ‘旺財’, ‘2020-09-29 00:00:00’, ‘女’, ‘五一廣場’, 2100);
INSERT INTO userinfo
COMMIT;
主鍵:SET FOREIGN_KEY_CHECKS = 1;
二、
在這之前大家記得匯入相關架包(因為使用的是maven空間,大家架包可以去maven中央倉庫去下載
三、建立一個轉賬的介面
四、配製資料庫連線
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!--<setting name="lazyLoadingEnabled" value="true"/>-->
<!--<setting name="aggressiveLazyLoading" value="false"/>-->
<!-- 開啟二級快取總開關 -->
<setting name="cacheEnabled" value="true"/>
</settings>
<typeAliases>
<package name="pojo"/>
<package name="vo"/>
</typeAliases>
<!-- 配置mybatis的環境資訊 -->
<environments default="development">
<environment id="development">
<!-- 配置JDBC事務控制,由mybatis進行管理 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置資料來源,採用dbcp連線池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/userinfo?useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 載入mapper -->
<mappers>
<!--<mapper resource="sqlmap/User.xml"/>-->
<package name="mapper"/>
</mappers>
</configuration>
五、使用MyBateis來生成資料庫相關語句、介面、實現類等
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="testTables" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自動生成的註釋 true:是 : false:否 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--資料庫連線的資訊:驅動類、連線地址、使用者名稱、密碼 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/userinfo"
userId="root"
password="123456">
</jdbcConnection>
<!-- <jdbcConnection driverClass="oracle.jdbc.OracleDriver"
connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:yycg"
userId="yycg"
password="yycg">
</jdbcConnection> -->
<!-- 預設false,把JDBC DECIMAL 和 NUMERIC 型別解析為 Integer,為 true時把JDBC DECIMAL 和
NUMERIC 型別解析為java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- targetProject:生成PO類的位置 -->
<javaModelGenerator targetPackage="po"
targetProject=".\src">
<!-- enableSubPackages:是否讓schema作為包的字尾 -->
<property name="enableSubPackages" value="false" />
<!-- 從資料庫返回的值被清理前後的空格 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- targetProject:mapper對映檔案生成的位置 -->
<sqlMapGenerator targetPackage="mapper"
targetProject=".\src">
<!-- enableSubPackages:是否讓schema作為包的字尾 -->
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- targetPackage:mapper介面生成的位置 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="mapper"
targetProject=".\src">
<!-- enableSubPackages:是否讓schema作為包的字尾 -->
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<table tableName="userinfo"
domainObjectName="Userinfo"
enableCountByExample="false"
enableDeleteByExample="false"
enableSelectByExample="false"
enableUpdateByExample="false"/>
</context>
</generatorConfiguration>
然後用測試類來生成介面和實現類(記得修改包的相關路徑)
@Test
public void testMBG() throws Exception{
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("mbg.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
}
}
生成了之後大家記得改變包的位置不然怕載入不了
六、建立實現類
@Configuration
public class ChangeMoneyImpl implements changmoney {
@Override
public boolean giveMoney(int on, int to, int money) {
SqlSession sqlSession= sqlSessionUtil.openSession();
UserinfoMapper mapper = sqlSession.getMapper(UserinfoMapper.class);
//轉錢人的資訊
Userinfo userinfo =mapper .selectByPrimaryKey(on);
int i=0;
if (userinfo!=null){
//設定轉錢人的餘額
userinfo.setMoney(userinfo.getMoney()-money);
//收影響的行數
i = mapper.updateByPrimaryKey(userinfo);
}
//被轉錢人的資訊
Userinfo userinfo2 =mapper .selectByPrimaryKey(to);
int j=0;
if (userinfo2!=null){
//設定轉錢人的餘額
userinfo2.setMoney(userinfo2.getMoney()+money);
//收影響的行數
j = mapper.updateByPrimaryKey(userinfo2);
}
if (i>0&&j>0){
System.out.println("轉錢成功");
//sqlSession.commit();
return true;
}else {
System.out.println("轉錢失敗");
//sqlSession.rollback();
return false;
}
}
}
七、構建SqlSessionFactory
public class sqlSessionUtil {
private static SqlSession sqlSession= null;
static {
//1、根據mybaits的配置檔案構建SqlSessionFactory
//需要改成我們自己的mybatis-config.xml的路徑
String resource = "SqlMapConfig.xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
e.printStackTrace();
}
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2、建立SqlSession
sqlSession= sqlSessionFactory.openSession();
}
public static SqlSession openSession() {
return sqlSession;
}
}
測試是可以轉轉成功的
接下來配置代理事務了
首先配置資料庫連線
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--1、載入資料庫的配置資訊 -->
<context:property-placeholder location="database.properties"/>
<!--2、datasource資料來源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${driver}" />
<property name="url" value="${url}"/>
<property name="username" value="${username2}"/>
<property name="password" value="${password}"/>
</bean>
<!-- 3、sqlSessionFactory -->
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 別名 -->
<property name="typeAliasesPackage" value="com.cc.model"></property>
<!-- mapper XML對映 -->
<property name="mapperLocations" value="classpath*:mapper/*Mapper.xml"></property>
<!-- 資料來源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.cc.mapper"></property>
</bean>
<!-- 5、事務管理 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
url=jdbc:mysql://localhost:3306/userinfo?useUnicode=true&&characterEncoding=utf-8
driver=com.mysql.jdbc.Driver
username2=root
password=123456
接下來就是配置事務代理
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
">
<!-- 1、啟動註解掃描-->
<!-- <context:annotation-config/> -->
<context:component-scan base-package="change"></context:component-scan>
<!-- 1)目標 -->
<bean id="target" class="change.ChangeMoneyImpl"></bean>
<!-- 2)黑客 -->
<bean id="transactionManager" class="proxy.TransactionManager"></bean>
<!--3)代理 -->
<bean id="ChangeMoneyImplProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="change.changmoney"></property>
<!-- 1)注入目標物件 -->
<property name="target" ref="target"/>
<!-- 2)黑客物件 -->
<property name="interceptorNames">
<array>
<value>transactionManager</value>
</array>
</property>
</bean>
</beans>
編寫實體代理類
public class TransactionManager implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation method) throws Throwable {
SqlSession sqlSession = sqlSessionUtil.openSession();
//呼叫目標方法
boolean result = (boolean) method.proceed();
if(result) {
sqlSession.commit();
System.out.println("====提交事務===");
}else {
sqlSession.rollback();
System.out.println("====回滾事務===");
}
return result;
}
}
最後在去進行測試
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:beans.xml"})
public class Test2 {
@Autowired
@Qualifier("ChangeMoneyImplProxy")
changmoney changmoney;
@Test
public void test1(){
boolean b = changmoney.giveMoney(1, 2, 30);
System.out.println(b);
}
}
所得結果為