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>								

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值