上一篇算是把JdbcDaoSupport的使用演示了一下,这篇主要是演示MappingSqlQuery、SqlUpdate、SqlFunction的使用以及Spring的事务管理。

一、MappingSqlQuery的使用

在上一篇获取所有User的方法QueryAllUser()中,使用getJdbcTemplate().queryForList()返回的是List<Map<String,Object>>类型,需要遍历转换成Java对象,那问题来了,查询的不止这一个方法,可能以后会有条件查询的方法,那每次都要把从数据库返回的List<Map<String,Object>>类型的List转一遍,当然也可以专门写一个转换的方法,这样每次传List<Map<String,Object>>类型的参数,然后返回List<User>类型的值。其实还有一种方式,就是使用MappingSqlQuery。MappingSqlQuery是一个抽象类,需要实现它的方法mapRow()。下面的代码就是定义了类UserMappingSqlQuery,继承了抽象类MappingSqlQuery,实现了它的mapRow()方法。

package Cuiyw.Spring.Dao;

import java.sql.ResultSet;
import java.sql.SQLException; import org.springframework.jdbc.object.MappingSqlQuery; import Cuiyw.Spring.Model.User; public class UserMappingSqlQuery extends MappingSqlQuery { @Override
protected Object mapRow(ResultSet rs, int rowNum) throws SQLException {
// TODO Auto-generated method stub
User user=new User();
user.setUserId((Integer)rs.getInt("id"));
user.setName((String)rs.getString("name"));
user.setMoney((Float)rs.getFloat("money"));
return user;
} }

上面定义之后就是该怎么使用了。还是UserDAO类中,重写List<User> QueryAllUser()方法。代码中主要是为了尝试使用参数,所有增加了一个过滤条件。

    public List<User> QueryAllUser() {

        String sql="select id,name,money from tb_user where name=?";
UserMappingSqlQuery userQuery=new UserMappingSqlQuery();
userQuery.setDataSource(getDataSource());
userQuery.setSql(sql);
userQuery.setParameters(new SqlParameter(java.sql.Types.VARCHAR));
userQuery.compile();
return userQuery.execute(new Object[]{new String("cuiywA")});
}

执行QueryAllUser(),打印出查询的list。

        List<User> list=userDao.QueryAllUser();
for(User u:list)
{
System.out.println("name:"+u.getName()+" money: "+u.getMoney());
}

二、SqlUpdate的使用

上面熟悉了查询的用法,SqlUpdate主要是用来更新。下面定义了UserSqlUpdate继承SqlUpdate

package Cuiyw.Spring.Dao;

import javax.sql.DataSource;

import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.object.SqlUpdate; public class UserSqlUpdate extends SqlUpdate{ public UserSqlUpdate(DataSource ds, String sql) {
super(ds, sql);
declareParameter(new SqlParameter(java.sql.Types.FLOAT) );
declareParameter(new SqlParameter(java.sql.Types.VARCHAR) );
} public int updateUserMoney(String name,float money)
{
compile();
return update(new Object[]{new Float(money),new String(name)});
}
}

上面的构造函数传两个参数,这两个参数我都放在上下文xml中。dataSource还是上一博客中配置的数据库信息。

<bean id="userSqlUpdate" class="Cuiyw.Spring.Dao.UserSqlUpdate">
<constructor-arg type="java.lang.String" index="1">
<value>update tb_user set money=? where name=?</value>
</constructor-arg>
<constructor-arg ref="dataSource" index="0"></constructor-arg>
</bean>
        UserSqlUpdate userSqlUpdate=(UserSqlUpdate)factory.getBean("userSqlUpdate");
userSqlUpdate.updateUserMoney("cuiywA",666);

在updateUserMoney()前后遍历数据库的user,发现以及修改了。


三、SqlFunction的使用

SqlFunction返回单一行的查询结果,默认返回int,也可以重载返回其他类型。下面的我是直接在main函数中使用。

        BasicDataSource dataSource=(BasicDataSource)factory.getBean("dataSource");
SqlFunction sf=new SqlFunction(dataSource,"select count(1) from tb_user;");
sf.compile();
int count=sf.run();
System.out.println("User Count:"+count);


四、Spring事务管理

什么是事务这些就不说了,事务最常见的例子就是转账,我定义User有money字段就是为了事务而定义的。实现事务在spring中有好几种方式,这里只简单介绍基于jdbc的声明式事务。

这里在IUserDAO中定义了两个接口,一个是存取款,一个是转账,并在UserDAO中实现。理想情况一个加一个减,但是加入减的成功了,加的失败了,那转账就是错误。

    public Boolean outInMoney(int toUserId,float money)
{
String sql="update tb_user set money=money+? where id=? ";
int row=getJdbcTemplate().update(sql, new Object[]{money,toUserId});
if(row>0)
{
return true;
}
return false;
} public Boolean transfer(int fromUserId, int toUserId, float transferMoney) {
Boolean out= outInMoney(fromUserId,-transferMoney);
Boolean in=outInMoney(toUserId,transferMoney);
return out&in;
}

spring使用DataSourceTransactionManager作为jdbc的事务管理者,被管理对象使用TransactionProxyFactoryBean配置。

1.配置DataSourceTransactionManager

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

2.配置TransactionProxyFactoryBean

这里transactionAttributes是来配置哪些方法使用事务管理,这里只配置了transfer方法,使用*,表达所有的方法,prop的值可以是PROPAGATION(事务的传播行为),ISOLATIONf(事务的隔离级别) -Exception(发生哪些异常回滚事务) +Exception(发生哪些事务不回滚)

PROPAGATION类型:

PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。 
PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作

Exception:
- 表示抛出该异常时需要回滚
+表示即使抛出该异常事务同样要提交
-ApplicationException :表示抛出ApplicationException 时,事务需要回滚。但不是说只抛出ApplicationException 异常时,事务才回滚,如果程序抛出RuntimeException和Error时,事务一样会回滚,即使这里没有配置。因为Spring中默认对所有的RuntimeException和Error都会回滚事务

 <!-- 配置业务层代理 -->
<bean id="userDaoProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!-- 配置目标对象 -->
<property name="target" ref="userDao"/>
<!-- 注入事务管理器 -->
<property name="transactionManager" ref="transactionManager"/>
<!-- 注入事务的属性 -->
<property name="transactionAttributes">
<props>
<prop key="transfer">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>

3.这里先理想情况的转账一个,可以看到cuiywA账号减100,cuiywB账号加100.

        List<User> list=userDao.QueryAllUser();
for(User u:list)
{
System.out.println("name:"+u.getName()+" money: "+u.getMoney());
}
userDao.transfer(1, 2, 100);
list=userDao.QueryAllUser();
for(User u:list)
{
System.out.println("name:"+u.getName()+" money: "+u.getMoney());
}

4.异常转账

模拟异常这里在转账时增加一个错误1/0

    public Boolean transfer(int fromUserId, int toUserId, float transferMoney) {
Boolean out= outInMoney(fromUserId,-transferMoney);
int a=1/0;
Boolean in=outInMoney(toUserId,transferMoney);
return out&in;
}

这里遇到了一个坑,配置之后还是按照前面的factory.getBean("userDao"),但始终不成功,找了好久,觉得配置的userDaoProxy并没有用到,这不科学啊,又百度了一下,发现还真是。在获取bean时不应时userDao了,而是TransactionProxyFactoryBean对象。

        IUserDAO userDao=(IUserDAO)factory.getBean("userDaoProxy");
          ApplicationContext context=new ClassPathXmlApplicationContext(new String[]{"ApplicationContext.xml"});
BeanFactory factory=context;
IUserDAO userDao=(IUserDAO)factory.getBean("userDaoProxy");
List<User> list=userDao.QueryAllUser();
for(User u:list)
{
System.out.println("name:"+u.getName()+" money: "+u.getMoney());
}
try
{
userDao.transfer(1, 2, 100);
}
catch(Exception e)
{}
list=userDao.QueryAllUser();
for(User u:list)
{
System.out.println("name:"+u.getName()+" money: "+u.getMoney());
}

上面在转账的地方增加了try-catch,主要是为了看执行转账之后的金额是否与之前的一致。上面截图可以看到是一致的,事务是有回滚的。事务管理还有其他方式,以后会一一介绍。

Spring之DAO二的更多相关文章

  1. Spring之DAO一

    前面博客把bean.aop简单了解了一下,今天主要是了解Spring中DAO层,如果使用传统的JDBC时需要创建连接.打开.执行sql.关闭连接这一系列的步骤,Spring框架对JDBC进行了封装,我 ...

  2. Spring IOC(二)容器初始化

    本系列目录: Spring IOC(一)概览 Spring IOC(二)容器初始化 Spring IOC(三)依赖注入 Spring IOC(四)总结 目录 一.ApplicationContext接 ...

  3. Spring Boot(十二):spring boot如何测试打包部署

    Spring Boot(十二):spring boot如何测试打包部署 一.开发阶段 1,单元测试 在开发阶段的时候最重要的是单元测试了,springboot对单元测试的支持已经很完善了. (1)在p ...

  4. Spring系列(二):Spring IoC应用

    一.Spring IoC的核心概念 IoC(Inversion of Control  控制反转),详细的概念见Spring系列(一):Spring核心概念 二.Spring IoC的应用 1.定义B ...

  5. Spring Security教程(二):自定义数据库查询

    Spring Security教程(二):自定义数据库查询   Spring Security自带的默认数据库存储用户和权限的数据,但是Spring Security默认提供的表结构太过简单了,其实就 ...

  6. spring boot / cloud (二) 规范响应格式以及统一异常处理

    spring boot / cloud (二) 规范响应格式以及统一异常处理 前言 为什么规范响应格式? 我认为,采用预先约定好的数据格式,将返回数据(无论是正常的还是异常的)规范起来,有助于提高团队 ...

  7. Spring【DAO模块】就是这么简单

    前言 上一篇Spring博文主要讲解了如何使用Spring来实现AOP编程,本博文主要讲解Spring的DAO模块对JDBC的支持,以及Spring对事务的控制... 对于JDBC而言,我们肯定不会陌 ...

  8. Spring Data(二)查询

    Spring Data(二)查询 接着上一篇,我们继续讲解Spring Data查询的策略. 查询的生成 查询的构建机制对于Spring Data的基础是非常有用的.构建的机制将截断前缀find-By ...

  9. spring boot / cloud (二十) 相同服务,发布不同版本,支撑并行的业务需求

    spring boot / cloud (二十) 相同服务,发布不同版本,支撑并行的业务需求 有半年多没有更新了,按照常规剧本,应该会说项目很忙,工作很忙,没空更新,吧啦吧啦,相关的话吧, 但是细想想 ...

随机推荐

  1. php 将pdf转成图片且将图片拼接

    说明: 1.pdf转图片通过安装php扩展imagick实现. 2.由于windows扩展安装的一系列问题,建议在linux环境开发,windows大伙可以尝试安装. 3.为Centos 安装Imag ...

  2. 独家探寻阿里安全潘多拉实验室,完美越狱苹果iOS11.2.1

    知道如何从攻击的视角去发现漏洞,才能建立更安全的体系,促进了整个生态的良性发展.以阿里安全潘多拉实验室为例,在对移动系统安全研究的过程中,把研究过程中发现的问题上报给厂商,促进系统安全性的提升. 小编 ...

  3. 【GISer&&Painter】GISer

    基于上一篇OpenGL的渲染原理,这两周又陆续接触了一些关于WebGL绘图的一些内容,因为刚入门,很多东西又很晦涩,所以特意花了小半天的时间整理了一下,特此记录. 一   画布和画笔:创建Canvas ...

  4. MySQL系列:基于binlog的增量订阅与消费(一)

    在一些业务场景中,像在数据分析中我们有时候需要捕获数据变化(CDC):在数据审计中,我们也往往需要知道数据从这个点到另一个点的变化:同样在实时分析中,我们有时候需要看到某个值得实时变化等. 要解决以上 ...

  5. 菜鸟版JAVA设计模式—外观模式

    外观模式是一种比較easy理解的模式,作用非常easy.就是解耦合. 结构也是非常easy,一个外观类.这个外观类持有非常多的业务类. 再由客户类去调用这个外观类去实现一些列的业务操作... 这个模式 ...

  6. BZOJ 1003 [ZJOI2006]物流运输trans SPFA+DP

    题意:链接 方法:SPFA+DP 解析:挺好的题目.因为数据范围较小所以用这样的方式能够搞,只是也是挺不好想的. 我们定义cost(i,j)表示从第i天走到第j天运用同一种方式的最小花费,然后因为数据 ...

  7. 【JAVA零基础入门系列】Day1 开发环境搭建

    [JAVA零基础入门系列](已完结)导航目录 Day1 开发环境搭建 Day2 Java集成开发环境IDEA Day3 Java基本数据类型 Day4 变量与常量 Day5 Java中的运算符 Day ...

  8. REST设计规则

    1.简介 REST(Representational State Transfer), 表述性状态转移是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格. REST只是一 ...

  9. Django的信号机制

    Django提供一种信号机制.其实就是观察者模式,又叫发布-订阅(Publish/Subscribe) .当发生一些动作的时候,发出信号,然后监听了这个信号的callback函数就会执行. Djang ...

  10. License友好的前端组件合集

    在做Web开发过程中,不可避免的会用到各种UI组件.通常,我们并不会需要什么组件,都去自己开发的,网上有那么多好用的,我们为什么要自己造轮子呢?我通常只会在网上找不到合适的组件时,才会去自己开发一套. ...