1. 程式人生 > >Spring練習:JDBC模板和事務回滾

Spring練習:JDBC模板和事務回滾

SSH框架是每個學生畢業前都必須掌握的一門技術,所以這裡就用Spring的JDBC模板和自定義異常讓事務回滾來做一個練習。主要用到的是spring和struts2框架來操作,這裡暫時沒用Hibernate來對資料進行操作。

一、練習要求。

要求寫一個使用者購買股票的專案,使用者先開戶後登陸,可以在裡面買股票和賣股票,當買股票金額超過使用者金額時就報異常讓事務回滾,使用者賣出股票時超過持有數量報異常讓事務回滾。

二、資料庫表

這裡因為沒有用到Hibernate所以不能通過配置實體類建立表,所以只能手動建立,表結構如下:

person表;


stock表


三、建立包和配置好所需的配置檔案

先匯入spring和struts2所需要用到的包,再建立配置檔案,然後我們再新建對應的Package。


四、開戶和登入

買或賣股票之前每個人都有自己的賬戶來存自己的金額和資訊,這裡先設計好jsp頁面讓使用者進行選擇是開戶還是登入。(這裡只是簡單的弄了下jsp頁面)


點選開戶就進到另一個jsp頁面來進行操作


到寫資料操作語句,這裡要先對使用者名稱進行排重下,以免重複賬戶。先到Dao層寫好介面,讓DaoImp層實現介面。


DaoImp實現介面時也要繼承下JdbcDaoSupport這樣才能對資料進行處理。

public class ZhuCeDaoImp extends JdbcDaoSupport implements ZhuCeDao{

	@Override
	public boolean addUser(Person p) {
		System.out.println("進入開戶~~~");
		//排重,如果為true就直接返回false;
		if(this.touser(p.getUserName())){
			return false;
		}
		//如果排除為false,就好進行新增使用者,這裡我們傳實體類就可以獲取到對應的引數。
		String sql = "insert into person(username,password,money) value (?,?,?)";
		//直接this關鍵字呼叫繼承父類的方法來操作sql語句
		int i  = this.getJdbcTemplate().update(sql,p.getUserName(),p.getPassWord(),p.getMoney());
		if(i!=0){
		//判斷下,在後臺輸出看是否成功
			System.out.println("開戶成功");
			return true;
		}else{
			System.out.println("開戶失敗");
			return false;
		}
	}
	//使用者名稱排重
	public boolean touser(String name){
		System.out.println("進入排重~~~");
		//查詢對應的使用者名稱
		String sql = "select username from person where username=?";
		List s = this.getJdbcTemplate().queryForList(sql, String.class,name);
		//存的是List型別,所以list不為空就是該使用者名稱已存在,反之則沒有
		if(s.size()!=0){
			return true;
		}
		return false;
	}
}
再寫Service層介面,讓ServiceImp層實現,Service層介面的方法就是Dao層介面的方法,所以為了方便集中把所以的Dao層介面方法都寫在了一個Service層接口裡面,ServiceImp層也是直接呼叫Dao層物件來實現全部方法。

Service層

public interface TestService {
	//使用者開戶
	public boolean addUser(Person p);
	//使用者登入
	public boolean toLogin(Person p);
	//買股票
	public boolean tobuy(String stockName,String username,int count) throws MyException;
	//賣股票
	public boolean tosell(String stockName,String username,int count) throws MyException;
	//獲取登入使用者的所以股票資訊
	public List<Stock> getUser(String userName);
	//獲取登入使用者的總價
	public double getMoney(String userName);
}
當用戶填寫完form表單後點擊開戶提交就會通過struts2呼叫對應的action層,action層再呼叫Service層來對資料進行操作,要配置好spring配置檔案。
public class ZhuCeKZ extends ActionSupport{
	//建立實體類,通過反射可以獲取到form表單的提交資料,
	//但form表單的名字必須和實體類屬性名相同,提供set,get方法,
	private Person p;
	public String toZhuCe(){
		//spring自動建立Service物件
		ApplicationContext ac = 
				new ClassPathXmlApplicationContext("applicationContext.xml");
		TestService ts = (TestService) ac.getBean("textS");
		//呼叫開戶處理,true就跳到登入檢視,false就跳回註冊檢視重新註冊
		if(ts.addUser(p)){
			return "success";
		}else{
		return "shibai";
		}
	}
	
	public Person getP() {
		return p;
	}

	public void setP(Person p) {
		this.p = p;
	}
}
成功註冊後,就進入登入的jsp頁面。


也是先寫好Dao層介面和讓DaoImp實現,再Service層介面讓ServiceImp實現

Dao層

public interface LoginDao {
	public boolean toLogin(Person p);
}
DaoImp層
public class LoginDaoImp extends JdbcDaoSupport implements LoginDao{

	@Override
	public boolean toLogin(Person p) {
		System.out.println("進入登入~~~");
		//先根據使用者名稱查下是否存在
		String sql = "select * from person where username=?";
		//因為Person不是基本資料型別,所以要先自定義型別下
		RowMapper<Person> rowMapper = new BeanPropertyRowMapper<Person>(Person.class); 
		List<Person> list = this.getJdbcTemplate().query(sql, rowMapper,p.getUserName());
		//存在List裡面,判斷下為空表示沒有改資料
		if(list.size()!=0){
		//不為空的話就讓查詢到的實體和登入的實體密碼就行判斷
		if(list.get(0).getPassWord().equals(p.getPassWord())){
			return true;
		}
		}
		return false;
	}
}

form表單提交跳到對應Action層,呼叫Service物件操作。
public class LoginKZ extends ActionSupport{
	private Person p;
	public String toLogin(){
		ApplicationContext ac = 
				new ClassPathXmlApplicationContext("applicationContext.xml");
		TestService ts = (TestService) ac.getBean("textS");
		if(ts.toLogin(p)){
			//把使用者名稱存進session裡面在頁面顯示下,和後面方便資料存取
			ActionContext.getContext().getSession().put("username", p.getUserName());
			return "success";
		}
		return "shibai";
	}
	public Person getP() {
		return p;
	}
	public void setP(Person p) {
		this.p = p;
	}
}

五、股票的買和賣

成功登入後就會跳到一個功能介面,用來購買股票和檢視使用者持有股。


當點選股票市場時就會進入檢視股票價格,買賣股票可以輸入對應的數量,所以用了些js來操作。


先寫好Dao層的資料操作。

Dao層介面

public interface TradeDao {
	//買股票
	public boolean tobuy(String stockName,String username,int count);
	//賣股票
	public boolean tosell(String stockName,String username,int count);
	//獲取登入使用者的所以股票資訊
	public List<Stock> getUser(String userName);
	//獲取登入使用者的總價
	public double getMoney(String userName);
}
DaoImp層
public class TradeDaoImp extends JdbcDaoSupport implements TradeDao{
	//買股票處理
	@Override
	public boolean tobuy(String stockName, String username, int count) {
		System.out.println(username+"買"+stockName+"股票數量:"+count);
		//呼叫寫好的排除股票重複方法
		if(this.getBuy(stockName, username)){
			//重複就直接更新股票數量
			String sql = "update stock set number=number+? where stockName=? and userName=?";
			this.getJdbcTemplate().update(sql,count,stockName,username);
			//呼叫寫好的(購買股票數量*股票價格)方法,來進行對使用者金額的加減
			double money = this.zeng(count, stockName);
			String sql2 = "update person set money=money-? where userName=?";
			this.getJdbcTemplate().update(sql2,money,username);
			System.out.println("購買股票成功");
			return true;
		}
		//如果排重為false就是新購買,所以要新新增股票資訊進資料庫
		String sql = "insert into stock(stockName,userName,number) value(?,?,?)";
		int i = this.getJdbcTemplate().update(sql,stockName,username,count);
		//如果成功就呼叫寫好的(購買股票數量*股票價格)方法,來進行對使用者金額的加減
		if(i!=0){
			double money = this.zeng(count, stockName);
			String sql2 = "update person set money=money-? where userName=?";
			this.getJdbcTemplate().update(sql2,money,username);
			System.out.println("購買股票成功");
			return true;
		}
		System.out.println("購買股票失敗");
		return false;
	}
	//賣股票處理
	@Override
	public boolean tosell(String stockName, String username, int count) {
		System.out.println(username+"賣"+stockName+"股票數量:"+count);
		//呼叫寫好的方法,判斷賣出數量是否超過持有數,超過就直接返回false
		int cou = this.getStock(stockName, username);
		if(cou<count){
			return false;
		}
		//呼叫排重方法,false就是沒持有改股票,true就是持有該股票
		if(this.getBuy(stockName, username)){
			//持有股票數量減去賣出數量
			String sql = "update stock set number=number-? where stockName=? and userName=?";
			this.getJdbcTemplate().update(sql,count,stockName,username);
			//呼叫寫好的(購買股票數量*股票價格)方法,來進行對使用者金額的加減
			double money = this.zeng(count, stockName);
			String sql2 = "update person set money=money+? where userName=?";
			this.getJdbcTemplate().update(sql2,money,username);
			return true;
		}
		return false;
	}
	//遍歷出使用者股票數量
	@Override
	public List<Stock> getUser(String userName) {
		System.out.println("遍歷使用者股票");
		String sql = "select * from stock where userName=?";
		//因為Stock不是基本資料型別,所以要先自定義型別下
		RowMapper<Stock> rowMapper = new BeanPropertyRowMapper<Stock>(Stock.class); 
		List<Stock> list =this.getJdbcTemplate().query(sql,rowMapper,userName);
		return list;
	}
	//獲取剩餘資產
	@Override
	public double getMoney(String userName) {
		String sql = "select money from person where userName=?";
		double money = this.getJdbcTemplate().queryForObject(sql, Double.class,userName);
		return money;
	}
	//自定義方法
	//股票排重
	public boolean getBuy(String stockName, String username){
		String sql = "select * from stock where stockName=?";
		RowMapper<Stock> rowMapper = new BeanPropertyRowMapper<Stock>(Stock.class); 
		List<Stock> list = this.getJdbcTemplate().query(sql,rowMapper,stockName);
		if(list.size()!=0){
		for(int i=0;i<list.size();i++){
		if(list.get(i).getUserName().equals(username)){
			return true;
		}}}
		return false;
	}
	//判斷型別對money進行加減
	public double zeng(int count,String type){
		double i = 0;
		//因為這裡沒存進資料庫,所以直接寫死
		if(type.equals("華為")){
			i = count*200;
		}
		if(type.equals("網易")){
			i = count*300;
		}
		if(type.equals("三星")){
			i = count*20;
		}
		return i;		
	}
	//獲取已有的股票數,來判斷是否超過賣出的數量
	public int getStock(String stockName,String userName){
		String sql = "select number from stock where stockName=? and userName=?";
		int i = this.getJdbcTemplate().queryForInt(sql, stockName,userName);
		return i;
	}
	
}

當用戶輸入數量點選買賣股票時,就會跳到對應的Action層來呼叫Service物件,ServiceImp層直接呼叫Dao層物件來操作。

public class StockKZ {
	//股票名,jsp頁面傳過來
	private String stockName;
	//股票數量,jsp頁面傳過來
	private int count;
	//登入使用者持有股票
	private ArrayList list;
	//總價
	private double money;
	//定義成成員變數方便呼叫
	ApplicationContext ac = 
			new ClassPathXmlApplicationContext("applicationContext.xml");
	//這裡呼叫的是代理物件
	TestService ts = (TestService) ac.getBean("serviceProxy");
	//買股票控制
	public String toBuy(){
		//使用者名稱在登入時已經存進session裡面,所以可以獲取到
		String username = ActionContext.getContext().getSession().get("username").toString();
		try {
			if(ts.tobuy(stockName, username, count)){
				return "success";
			}
		} catch (MyException e) {
			e.printStackTrace();
		}
		return "shibai";
	}
	//賣股票控制
	public String toSell(){
		String username = ActionContext.getContext().getSession().get("username").toString();
		try {
			if(ts.tosell(stockName, username, count)){
				return "success";
			}
		} catch (MyException e) {
			e.printStackTrace();
		}
		return "shibai";
	}
	//檢視資產和持股票數量
	public String getZiCang() {
		String userName = ActionContext.getContext().getSession().get("username").toString();
		list = (ArrayList) ts.getUser(userName);
		money = ts.getMoney(userName);
		return "success2";
	}
	//set,get
	public void setStockName(String stockName) {
		this.stockName = stockName;
	}
	public int getCount() {
		return count;
	}
	public void setCount(int count) {
		this.count = count;
	}
	public void setList(ArrayList list) {
		this.list = list;
	}
	public ArrayList getList() {
		return list;
	}
	public double getMoney() {
		return money;
	}
	public void setMoney(double money) {
		this.money = money;
	}
}

這樣就可以買賣股票,在頁面上顯示登入使用者持有股票和剩餘金額


六、事務的回滾

如何讓事務回滾,這裡就要自定義異常,當有異常時就會讓事務回滾,從而讓資料沒有改變。所以我們在買賣股票時加下判斷,這裡就要到ServiceImp層操作

public class TestServiceImp implements TestService{
	//開戶Dao
	private ZhuCeDao zd;
	//登入Dao
	private LoginDao ld;
	//股票操作Dao
	private TradeDao td;
	//使用者開戶
	@Override
	public boolean addUser(Person p) {
		return zd.addUser(p);
	}
	//使用者登入
	@Override
	public boolean toLogin(Person p) {
		return ld.toLogin(p);
	}
	//買股票
	@Override
	public boolean tobuy(String stockName, String username, int count) throws MyException {
		td.tobuy(stockName, username, count);
		//獲取下剩餘的資產
		double money = this.getMoney(username);
		//如果小於0就拋異常,讓事務回滾
		if(money<0){
			throw new MyException("你已經沒有錢了~~~");
		}
		return true;
	}
	//賣股票
	@Override
	public boolean tosell(String stockName, String username, int count) throws MyException {
		//獲取下使用者的全部持有股票資訊
		List list = this.getUser(username);
		if(list.size()!=0){
			//不為空就遍歷
			for(int i=0;i<list.size();i++){
				Stock stock = (Stock) list.get(i);
				//匹配股票名字是否相同,相同就判斷使用者持有該股票數量
				//如果小於等於0就拋異常,讓事務回滾
				if(stockName.equals(stock.getStockName())&&stock.getNumber()<=0){
					throw new MyException("你已經沒有該公司的股票~~~"); 
				}
			}
		}
		return td.tosell(stockName, username, count);
	}
	//登入使用者持有股票
	@Override
	public List<Stock> getUser(String userName){
		List list = td.getUser(userName);
		return list;
	}
	//獲取總價
	@Override
	public double getMoney(String userName) {
		return td.getMoney(userName);
	}

	//set
	public void setZd(ZhuCeDao zd) {
		this.zd = zd;
	}
	public void setLd(LoginDao ld) {
		this.ld = ld;
	}
	public void setTd(TradeDao td) {
		this.td = td;
	}

}
如果丟擲異常後臺就會輸出異常資訊。



最後

spring的配置檔案才是最重要的,所以來看下applicationContext.xml的配置

<?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 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">
 		
        
		 <!-- 註冊資料來源 (spring內建資料庫源)-->  
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        	<property name="driverClassName"  value="${jdbc.driver}"/>
        	<property name="url"  value="${jdbc.url}"/>
        	<property name="username"  value="${jdbc.username}" />
        	<property name="password"  value="${jdbc.password}" />
        </bean>
        <!-- 註冊資料庫屬性檔案 方式一  --> 
        <bean	class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        	<property name="location" value="classpath:jdbc.properties" />
        </bean> 
        <!-- 註冊事務管理器 -->
        <bean	id="transactionManager" 
        	class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        	<property name="dataSource" ref="dataSource"></property>
        </bean>
  		<!-- 生成service的事務代理物件 -->
  		<bean id="serviceProxy"
  			class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
  		<!-- 	目標物件 -->
  			<property name="target" ref="textS" />
  			<!-- 跟事務管理器關聯 -->
  			<property name="transactionManager" ref="transactionManager" />
  			<property name="transactionAttributes">
  					<props>
  						<prop key="to*">ISOLATION_DEFAULT,PROPAGATION_REQUIRED,-MyException</prop>
  					</props>
  			</property>
  		</bean>
        <!-- 註冊Dao物件 -->   
        <!-- 開戶Dao -->    
        <bean id="zhuceD" class="com.it.DaoImp.ZhuCeDaoImp">
        	<property name="dataSource" ref="dataSource"></property>
        </bean>
        <!-- 登入Dao -->
        <bean id="loginD" class="com.it.DaoImp.LoginDaoImp">
        	<property name="dataSource" ref="dataSource"></property>
        </bean>
        <!-- 股票操作Dao -->
        <bean id="tradeD" class="com.it.DaoImp.TradeDaoImp">
        	<property name="dataSource" ref="dataSource"></property>
        </bean>
        <!-- 註冊Service物件 -->       
        <bean id="textS" class="com.it.ServiceImp.TestServiceImp">
        	<property name="zd" ref="zhuceD"></property>
        	<property name="ld" ref="loginD"></property>
        	<property name="td" ref="tradeD"></property>
        </bean>
</beans>								

相關推薦

Spring練習JDBC模板事務

SSH框架是每個學生畢業前都必須掌握的一門技術,所以這裡就用Spring的JDBC模板和自定義異常讓事務回滾來做一個練習。主要用到的是spring和struts2框架來操作,這裡暫時沒用Hibernate來對資料進行操作。 一、練習要求。 要求寫一個使用者購買股票的專案,使

四、springJDBC模板事務管理

Spring的JDBC模板 Spring是JavaEE開發的一站式框架,對各種持久化技術都提供了簡單的模板 ORM持久化技術 模板類 JDBC org.springframework.jdbc.core.JdbcTemplate

事務事務

mysq back 事務 sql 結束 cti 數據庫 ons transacti 1、定義:一件事從開始發生到結束的整個過程 2、作用:確保數據的一致性 3、事務和事務回滾的應用   1、SQL命令會 autocommit 到數據庫執行   2、事務操作

Spring入門(三)— AOP註解、jdbc模板事務

list() 規範 行數 get attribute 樂觀鎖 過濾 callback 賬號 一、AOP註解開發 導入jar包 aop聯盟包、 aspectJ實現包 、 spring-aop-xxx.jar 、 spring-aspect-xxx.jar 導入約束 a

Day3-Spring事務管理、Spring框架的JDBC模板

今天內容 1. Spring框架的AOP之註解的方式2. Spring框架的JDBC模板3. Spring框架的事務管理 案例一:使用Spring框架的AOP技術對DAO層的功能進行增強 案例一:使用Spring框架的AOP技術對DAO層的功能進行增強 1. 使用Spring框架的

spring事務管理,基於xml配置完成事務spring中資料庫表中欄位名pojo中屬性名不一致時候,實現RowMapper介面手動封裝

宣告使用JDK8,spring5.0.7, 測試說明: service 層 宣告介面進行轉賬,從A轉賬B ,然後對AB 進行更新操作,在事務中對find方法開啟 只讀許可權,無法進行更新操作,造成事務回滾進行測試事務; 主要測試方法:* void tra

Spring--04(SpringJDBC操作事務操作)

1.Spring 的 JDBC 的模板      Spring 提供了很多持久層技術的模板類簡化程式設計:                      

Java學習筆記(12)Spring JDBC框架事務管理

Spring JDBC框架 JDBC框架概述: 在使用普通的 JDBC 資料庫時,就會很麻煩的寫不必要的程式碼來處理異常,開啟和關閉資料庫連線等。但 Spring JDBC 框架負責所有的低層細節,從開始開啟連線,準備和執行 SQL 語句,處理異常,處理

事務 spring+hibernate實現事務及其他

程式碼控制的事務管理2. 引數化配置的事務管理下面就這兩種方式進行介紹。u 程式碼控制的事務管理首先,進行以下配置,假設配置檔案為(Application-Context.xml):<beans><bean id="dataSource" class="org.apache.commons.

java之Spring事務Ehcache配置

弄了一大早,終於配好了事務,事務的掃描包配好,Ehcache就是切面的問題,一切問題也迎刃而解。。。 一、Spring事務回滾 1、applicationContext.xml中配置 <!--spring 掃包 @Service .....

Spring事務異常類

1、異常的一些基本知識 異常的架構   異常的繼承結構:Throwable為基類,Error和Exception繼承Throwable。Error和RuntimeException及其子類成為未檢查異常(unchecked),其它異常成為已檢查異常(checked)。  

Spring 實現部分事務

light back true prop 回滾 sage .class lba aaa 例如有業務需求,在catch異常後,catch塊內把異常的信息存入到數據庫,而catch外的數據全部回滾 try { ....... aaaService.save();

的意義---JDBC事務探究

final cti span net etc rom tle img round JDBC手動事務提交回滾的常見寫法一直是rollback寫在commit的catch之後: try{ conn.setAutoCommit(false);   ps.execu

spring框架總結(04)----介紹的是Spring中的JDBC模板

aos 不用 get interface comm use clas table oid 1.1 Jdbc模板概述 它是spring框架中提供的一個對象,是對原始Jdbc API對象的簡單封裝。spring框架為我們提供了很多的操作模板類,入下圖所示: 我們今天的

淺談Spring中的事務

spec style try 常見 產生原因 turn prop ret run 使用Spring管理事務過程中,碰到過一些坑,因此也稍微總結一下,方便後續查閱。1.代碼中事務控制的3種方式編程式事務:就是直接在代碼裏手動開啟事務,手動提交,手動回滾。優點就是可以靈

哪些異常是RuntimeException?Sql異常屬於RuntimeException嗎?Spring下SQL異常事務

tail 好的 duplicate 代碼 blog 後拋 ase owa 接口文檔 一,為什麽框架中根本沒有對Exception的一般子類進行回滾配置,異常發生時,事務都進行了回滾 ,說好的只會對RuntimeException(Unchecked 非受檢異常)回滾呢?

Python實踐練習電話號碼 E-mail 地址提取程序

system 剪切板 http con cisco jobs 什麽 python3 sts 題目: 假設你有一個無聊的任務,要在一篇長的網頁或文章中,找出所有電話號碼和郵件地址。如果手動翻頁,可能需要查找很長時間。如果有一個程序,可以在剪貼板的文本中查找電話號碼和 E-ma

spring事務的多種方式

轉:https://www.cnblogs.com/zeng1994/p/8257763.html start 看下下面的說明,會對理解本人貼出的程式碼有幫助。 1.程式碼中事務控制的3種方式 程式設計式事務:就是直接在程式碼裡手動開啟事務,手動提交,手動回滾。優點就是可以靈活控制,缺點

Spring Cloud配置中心訊息匯流排(終結版)(09)

我們在springcloud(七):配置中心svn示例和refresh中講到,如果需要客戶端獲取到最新的配置資訊需要執行refresh,我們可以利用webhook的機制每次提交程式碼傳送請求來重新整理客戶端,當客戶端越來越多的時候,需要每個客戶端都執行一遍,這種方案就不太適合了。使用Spring C

spring手動控制事務

在catch語塊中增加TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); import org.springframework.transaction.interceptor.TransactionAs