zoukankan      html  css  js  c++  java
  • Spring之DAO二

    上一篇算是把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;
        }
    
    }
    View Code

    上面定义之后就是该怎么使用了。还是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")});
        }
    View Code

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

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

     二、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)});
        }
    }
    View Code

    上面的构造函数传两个参数,这两个参数我都放在上下文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>
    View Code
            UserSqlUpdate userSqlUpdate=(UserSqlUpdate)factory.getBean("userSqlUpdate");
            userSqlUpdate.updateUserMoney("cuiywA",666); 
    View Code

    在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);
    View Code


    四、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;
        }
    View Code

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

    1.配置DataSourceTransactionManager

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

    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>
    View Code

     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());
            }
    View Code

    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;
        }
    View Code

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

            IUserDAO userDao=(IUserDAO)factory.getBean("userDaoProxy");
    View Code
              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());
            }
    View Code

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

  • 相关阅读:
    OutputCache 缓存key的创建 CreateOutputCachedItemKey
    Asp.net Web Api源码调试
    asp.net mvc源码分析DefaultModelBinder 自定义的普通数据类型的绑定和验证
    Asp.net web Api源码分析HttpParameterBinding
    Asp.net web Api源码分析HttpRequestMessage的创建
    asp.net mvc源码分析ActionResult篇 RazorView.RenderView
    Asp.Net MVC 项目预编译 View
    Asp.net Web.config文件读取路径你真的清楚吗?
    asp.net 动态创建TextBox控件 如何加载状态信息
    asp.net mvc源码分析BeginForm方法 和ClientValidationEnabled 属性
  • 原文地址:https://www.cnblogs.com/5ishare/p/8213370.html
Copyright © 2011-2022 走看看