Spring练习:JDBC模板和事务回滚

来源:互联网 发布:诺基亚6730c软件 编辑:程序博客网 时间:2024/06/03 07:13

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{@Overridepublic 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{@Overridepublic 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{//买股票处理@Overridepublic 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;}//卖股票处理@Overridepublic boolean tosell(String stockName, String username, int count) {System.out.println(username+"卖"+stockName+"股票数量:"+count);//调用写好的方法,判断卖出数量是否超过持有数,超过就直接返回falseint 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;}//遍历出用户股票数量@Overridepublic 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;}//获取剩余资产@Overridepublic 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,getpublic 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{//开户Daoprivate ZhuCeDao zd;//登录Daoprivate LoginDao ld;//股票操作Daoprivate TradeDao td;//用户开户@Overridepublic boolean addUser(Person p) {return zd.addUser(p);}//用户登录@Overridepublic boolean toLogin(Person p) {return ld.toLogin(p);}//买股票@Overridepublic 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;}//卖股票@Overridepublic 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);}//登录用户持有股票@Overridepublic List<Stock> getUser(String userName){List list = td.getUser(userName);return list;}//获取总价@Overridepublic double getMoney(String userName) {return td.getMoney(userName);}//setpublic 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>        <!-- 注册数据库属性文件 方式一  -->         <beanclass="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">        <property name="location" value="classpath:jdbc.properties" />        </bean>         <!-- 注册事务管理器 -->        <beanid="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>

0 0