1,Data access with JDBC

使用springJdbc非常简单。在我们写daoImpl的时候只需要继承spring的org.springframework.jdbc.core.support.JdbcDaoSupport该类。在实现以下需要实现的接口即可,再在需要实现的接口方法中使用通过继承JdbcDaoSupport类的jdbcTemplate对象的update、execute、query等方法完成我们需要的方法即可。

比如我们要写一个UserDaoImpl类泽代码如下:

package com.xiaohui.jdbc;import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.PreparedStatementCallback;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.support.JdbcDaoSupport;public class UserDaoImpl extends JdbcDaoSupport implements IUserDao {@Overridepublic void save(User u) {String sql = "INSERT INTO user VALUES(NULL,?)";this.getJdbcTemplate().update(sql, u.getName());}@Overridepublic void update(User u) {String sql = "UPDATE  user SET name =? WHERE id=?";this.getJdbcTemplate().update(sql, u.getName(), u.getId());}@Overridepublic void delete(Long id) {this.getJdbcTemplate().execute("delete from user where id=" + id);}@Overridepublic List<User> list() {String sql = "SELECT * FROM user";List<User> users = this.getJdbcTemplate().query(sql,new ResultSetExtractor<List<User>>() {@Overridepublic List<User> extractData(ResultSet rs)throws SQLException, DataAccessException {List<User> userList = new ArrayList<User>();while (rs.next()) {User user = new User();user.setId(rs.getLong("id"));user.setName(rs.getString("name"));userList.add(user);}return userList;}});return users;}@Overridepublic User getById(final Long id) {String sql = "select * from user where id=?";User u = this.getJdbcTemplate().execute(sql,new PreparedStatementCallback<User>() {@Overridepublic User doInPreparedStatement(PreparedStatement ps)throws SQLException, DataAccessException {ps.setLong(1, id);ResultSet set = ps.executeQuery();while (set.next()) {User u = new User();u.setId(id);u.setName(set.getString("name"));return u;}return null;}});return u;}
}

同时我们需要给属性jdbcTemplate在xml中配置属性值xml如下:需要在source folder目录下创建一个jdbc.properties。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd"><context:property-placeholder location="classpath:jdbc.properties"/><bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"><property name="driverClassName" value="${jdbc.driverClassName}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></bean><bean id="template" class="org.springframework.jdbc.core.JdbcTemplate" scope="prototype"><property name="dataSource" ref="dataSource"/></bean><bean id="userdao" class="com.xiaohui.jdbc.UserDaoImpl"><property name="jdbcTemplate" ref="template"/></bean>
</beans>

这样我们就可以通过获取userdao 来与数据库交互了。

2,spring事务管理

事务是一组操作的执行单元,相对于数据库操作来讲,事务管理的是一组SQL指令,比如增加,修改,删除等,事务的一致性,要求,这个事务内的操作必须全部执行成功,如果在此过程种出现了差错,比如有一条SQL语句没有执行成功,那么这一组操作都将全部回滚。

事务特性:

  • atomic(原子性):要么都发生,要么都不发生。
  • consistent(一致性):数据应该不被破坏。
  • solate(隔离性):用户间操作不相混淆。
  • Durable(持久性):永久保存,例如保存到数据库中等。

spring提供的两种事务管理方式 基于xml的事务管理和基于aop注解的管理事务。在spring中spring没有直接管理事务,而是将管理事务的责任委托给JTA或相应的持久性机制所提供的某个特定平台的事务实现

事务管理器实现 目标
org.springframework.jdbc.datasource.DataSourceTransactionManager 在单一的JDBC Datasource中的管理事务
org.springframework.orm.hibernate3.HibernateTransactionManager 当持久化机制是hibernate时,用它来管理事务
org.springframework.jdo.JdoTransactionManager 当持久化机制是Jdo时,用它来管理事务。
org.springframework.transaction.jta.JtaTransactionManager 使用一个JTA实现来管理事务。在一个事务跨越多个资源时必须使用
org.springframework.orm.ojb.PersistenceBrokerTransactionManager 当apache的ojb用作持久化机制时,用它来管理事务。

 

理解事务属性–事物传播规则

  • REQUIRED    :业务方法需要在一个事务中运行。如果方法运行时,已经处在一个事务中,那么加入到该事务,否则为自己创建一个新的事务
  • NOT_SUPPORTED :声明方法不需要事务。如果方法没有关联到一个事务,容器不会为它开启事务。如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会恢复执行
  • REQUIRESNEW属性表明不管是否存在事务,业务方法总会为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务会被挂起,新的事务会被创建,直到方法执行结束,新事务才算结束,原先的事务才会恢复执行
  • MANDATORY:该属性指定业务方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果业务方法在没有事务的环境下调用,容器就会抛出例外
  • SUPPORTS这一事务属性表明,如果业务方法在某个事务范围内被调用,则方法成为该事务的一部分。如果业务方法在事务范围外被调用,则方法在没有事务的环境下执行
  • Never:指定业务方法绝对不能在事务范围内执行。如果业务方法在某个事务中执行,容器会抛出例外,只有业务方法没有关联到任何事务,才能正常执行
  • NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按REQUIRED属性执行.它使用了一个单独的事务, 这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效

1,基于注解的方式管理事务。

基于注解的使用比较简单,只要在xml中引入tx命名空间,并配置事务管理器transactionManager  xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-3.0.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.0.xsd"><!-- springJdbc --><context:property-placeholder location="jdbc.properties" /><bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close" ><property name="driverClassName" value="${jdbc.driverClassName}" /><property name="url" value="${jdbc.url}" /><property name="username" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /></bean><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean><tx:annotation-driven transaction-manager="transactionManager" /><bean id="accDao" class="com.xiaohui.trans.AccountDaoImpl"><property name="dataSource" ref="dataSource" /></bean><bean id="accountService" class="com.xiaohui.trans.AccountServiceImpl"><property name="dao" ref="accDao"></property></bean>
</beans>

 这时在业务层需要开启事务的方法上面加上@Transactional注解即可。

@Transactional
public void trans(Account accIn, Account accOut, Double amount) {// 转出金额dao.transOut(accOut, amount);// 转入金额dao.transIn(accIn, amount);
}

如上则在转账的过程里出现任何异常事物会回滚,都不会影响到数据库底层数据的。

2,基于xml配置的事务管理

使用xml配置管理事务,我们同样需要告诉spring容器,我们使用具体的什么管理器,jdbc的还是hibernate的,所以还需要配置transactionManager,这次我们需要使用aop来管理我们的事物。

这次我们需要加入aop的命名空间,再将上面的

<tx:annotation-driven transaction-manager="transactionManager" />

xml代码替换为:

<aop:config><aop:pointcut expression="execution(* com.xiaohui.trans.*ServiceImpl.*(..))" id="pointcut"/><aop:advisor advice-ref="transAdvice" pointcut-ref="pointcut"/></aop:config><tx:advice id="transAdvice"><tx:attributes><tx:method name="trans"/><tx:method name="transIn" propagation="REQUIRED"/><tx:method name="transOut" propagation="REQUIRED"/></tx:attributes></tx:advice>

即可。