`
jetway
  • 浏览: 483727 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

Spring jdbc

    博客分类:
  • java
阅读更多

Spring的JDBC框架能够承担资源管理和异常处理的工作,从而简化我们的JDBC代码,
让我们只需编写从数据库读写数据所必需的代码。Spring把数据访问的样板代码隐藏到模板类之下,
结合Spring的事务管理,可以大大简化我们的代码.

Spring提供了3个模板类:

JdbcTemplate:Spring里最基本的JDBC模板,利用JDBC和简单的索引参数查询提供对数据库的简单访问。
NamedParameterJdbcTemplate:能够在执行查询时把值绑定到SQL里的命名参数,而不是使用索引参数。
SimpleJdbcTemplate:利用Java 5的特性,比如自动装箱、通用(generic)和可变参数列表来简化JDBC模板的使用。
具体使用哪个模板基本上取决于个人喜好。


使用Spring的JdbcTemplate来实现简单的增删改查,首先建立测试数据表person
create table person(
id int not null primary key auto_increment,
name varchar(20) not null
)

导入依赖的jar包,由于测试中数据源使用的是dbcp数据源,需要以下jar包支持:
commons-logging.jar
commons-pool.jar
commons-dbcp.jar
同时还必须导入数据库驱动jar包:mysql-connector-java-3.1.8-bin.jar

建立实体bean
Person.java
Java代码
package com.royzhou.jdbc;  
 
public class PersonBean {  
    private int id;  
    private String name;  
 
    public PersonBean() {  
    }  
      
    public PersonBean(String name) {  
        this.name = name;  
    }  
      
    public PersonBean(int id, String name) {  
        this.id = id;  
        this.name = name;  
    }  
       
    public int getId() {  
        return id;  
    }  
 
    public void setId(int id) {  
        this.id = id;  
    }  
 
    public String getName() {  
        return name;  
    }  
 
    public void setName(String name) {  
        this.name = name;  
    }  
      
    public String toString() {  
        return this.id + ":" + this.name;  
    }  

package com.royzhou.jdbc;

public class PersonBean {
 private int id;
 private String name;

 public PersonBean() {
 }
 
 public PersonBean(String name) {
  this.name = name;
 }
 
 public PersonBean(int id, String name) {
  this.id = id;
  this.name = name;
 }
 
 public int getId() {
  return id;
 }

 public void setId(int id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }
 
 public String toString() {
  return this.id + ":" + this.name;
 }
}


接口类:
PersonService.java
Java代码
package com.royzhou.jdbc;  
 
import java.util.List;  
 
public interface PersonService {  
      
    public void addPerson(PersonBean person);  
      
    public void updatePerson(PersonBean person);  
      
    public void deletePerson(int id);  
      
    public PersonBean queryPerson(int id);  
      
    public List<PersonBean> queryPersons();  

package com.royzhou.jdbc;

import java.util.List;

public interface PersonService {
 
 public void addPerson(PersonBean person);
 
 public void updatePerson(PersonBean person);
 
 public void deletePerson(int id);
 
 public PersonBean queryPerson(int id);
 
 public List<PersonBean> queryPersons();
}


实现类:
PersonServiceImpl.java
Java代码
package com.royzhou.jdbc;  
 
import java.util.List;  
 
import javax.sql.DataSource;  
import java.sql.Types;  
 
import org.springframework.jdbc.core.JdbcTemplate;  
 
public class PersonServiceImpl implements PersonService {  
 
    private JdbcTemplate jdbcTemplate;  
      
    /** 
     * 通过Spring容器注入datasource 
     * 实例化JdbcTemplate,该类为主要操作数据库的类 
     * @param ds 
     */ 
    public void setDataSource(DataSource ds) {  
        this.jdbcTemplate = new JdbcTemplate(ds);  
    }  
      
    public void addPerson(PersonBean person) {  
        /** 
         * 第一个参数为执行sql 
         * 第二个参数为参数数据 
         * 第三个参数为参数类型 
         */ 
        jdbcTemplate.update("insert into person values(null,?)", new Object[]{person.getName()}, new int[]{Types.VARCHAR});  
    }  
 
    public void deletePerson(int id) {  
        jdbcTemplate.update("delete from person where id = ?", new Object[]{id}, new int[]{Types.INTEGER});  
    }  
 
    public PersonBean queryPerson(int id) {  
        /** 
         * new PersonRowMapper()是一个实现RowMapper接口的类, 
         * 执行回调,实现mapRow()方法将rs对象转换成PersonBean对象返回 
         */ 
        PersonBean pb = (PersonBean) jdbcTemplate.queryForObject("select id,name from person where id = ?", new Object[]{id}, new PersonRowMapper());  
        return pb;  
    }  
 
    @SuppressWarnings("unchecked")  
    public List<PersonBean> queryPersons() {  
        List<PersonBean> pbs = (List<PersonBean>) jdbcTemplate.query("select id,name from person", new PersonRowMapper());  
        return pbs;  
    }  
 
    public void updatePerson(PersonBean person) {  
        jdbcTemplate.update("update person set name = ? where id = ?", new Object[]{person.getName(), person.getId()}, new int[]{Types.VARCHAR, Types.INTEGER});  
    }  

package com.royzhou.jdbc;

import java.util.List;

import javax.sql.DataSource;
import java.sql.Types;

import org.springframework.jdbc.core.JdbcTemplate;

public class PersonServiceImpl implements PersonService {

 private JdbcTemplate jdbcTemplate;
 
 /**
  * 通过Spring容器注入datasource
  * 实例化JdbcTemplate,该类为主要操作数据库的类
  * @param ds
  */
 public void setDataSource(DataSource ds) {
  this.jdbcTemplate = new JdbcTemplate(ds);
 }
 
 public void addPerson(PersonBean person) {
  /**
   * 第一个参数为执行sql
   * 第二个参数为参数数据
   * 第三个参数为参数类型
   */
  jdbcTemplate.update("insert into person values(null,?)", new Object[]{person.getName()}, new int[]{Types.VARCHAR});
 }

 public void deletePerson(int id) {
  jdbcTemplate.update("delete from person where id = ?", new Object[]{id}, new int[]{Types.INTEGER});
 }

 public PersonBean queryPerson(int id) {
  /**
   * new PersonRowMapper()是一个实现RowMapper接口的类,
   * 执行回调,实现mapRow()方法将rs对象转换成PersonBean对象返回
   */
  PersonBean pb = (PersonBean) jdbcTemplate.queryForObject("select id,name from person where id = ?", new Object[]{id}, new PersonRowMapper());
  return pb;
 }

 @SuppressWarnings("unchecked")
 public List<PersonBean> queryPersons() {
  List<PersonBean> pbs = (List<PersonBean>) jdbcTemplate.query("select id,name from person", new PersonRowMapper());
  return pbs;
 }

 public void updatePerson(PersonBean person) {
  jdbcTemplate.update("update person set name = ? where id = ?", new Object[]{person.getName(), person.getId()}, new int[]{Types.VARCHAR, Types.INTEGER});
 }
}


PersonRowMapper.java
Java代码
package com.royzhou.jdbc;  
 
import java.sql.ResultSet;  
import java.sql.SQLException;  
 
import org.springframework.jdbc.core.RowMapper;  
 
public class PersonRowMapper implements RowMapper {  
    //默认已经执行rs.next(),可以直接取数据  
    public Object mapRow(ResultSet rs, int index) throws SQLException {  
        PersonBean pb = new PersonBean(rs.getInt("id"),rs.getString("name"));  
        return pb;  
    }  

package com.royzhou.jdbc;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.jdbc.core.RowMapper;

public class PersonRowMapper implements RowMapper {
 //默认已经执行rs.next(),可以直接取数据
 public Object mapRow(ResultSet rs, int index) throws SQLException {
  PersonBean pb = new PersonBean(rs.getInt("id"),rs.getString("name"));
  return pb;
 }
}


我们需要在bean.xml中配置DataSource,并且将datasource注入到我们的业务类中

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"   
       xmlns:aop="http://www.springframework.org/schema/aop
       xsi:schemaLocation="http://www.springframework.org/schema/beans  
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd  
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> 
 
     <context:property-placeholder location="classpath:jdbc.properties"/> 
     <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 
        <property name="driverClassName" value="${driverClassName}"/> 
        <property name="url" value="${url}"/> 
        <property name="username" value="${username}"/> 
        <property name="password" value="${password}"/> 
         <!-- 连接池启动时的初始值 --> 
         <property name="initialSize" value="${initialSize}"/> 
         <!-- 连接池的最大值 --> 
         <property name="maxActive" value="${maxActive}"/> 
         <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 --> 
         <property name="maxIdle" value="${maxIdle}"/> 
         <!--  最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 --> 
         <property name="minIdle" value="${minIdle}"/> 
     </bean> 
      
</beans> 

<?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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

  <context:property-placeholder location="classpath:jdbc.properties"/>
  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
     <property name="driverClassName" value="${driverClassName}"/>
     <property name="url" value="${url}"/>
     <property name="username" value="${username}"/>
     <property name="password" value="${password}"/>
      <!-- 连接池启动时的初始值 -->
   <property name="initialSize" value="${initialSize}"/>
   <!-- 连接池的最大值 -->
   <property name="maxActive" value="${maxActive}"/>
   <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
   <property name="maxIdle" value="${maxIdle}"/>
   <!--  最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->
   <property name="minIdle" value="${minIdle}"/>
  </bean>
 
</beans>


jdbc.properties
Java代码
driverClassName=org.gjt.mm.mysql.Driver  
url=jdbc:mysql://localhost:3306/royzhou?useUnicode=true&characterEncoding=UTF-8  
username=root  
password=123456 
initialSize=1 
maxActive=500 
maxIdle=2 
minIdle=1 

driverClassName=org.gjt.mm.mysql.Driver
url=jdbc:mysql://localhost:3306/royzhou?useUnicode=true&characterEncoding=UTF-8
username=root
password=123456
initialSize=1
maxActive=500
maxIdle=2
minIdle=1


编写我们的测试类:TestJdbcTemplate.java
Java代码
package com.royzhou.jdbc;  
 
import org.springframework.context.ApplicationContext;  
import org.springframework.context.support.ClassPathXmlApplicationContext;  
 
public class TestJdbcTemplate {  
    public static void main(String[] args) {  
        ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");  
        PersonService ps = (PersonService)ctx.getBean("personService");  
        ps.addPerson(new PersonBean("royzhou"));  
        PersonBean pb = ps.queryPerson(1);  
        System.out.println(pb);  
        pb.setName("haha");  
        ps.updatePerson(pb);  
        pb = ps.queryPerson(1);  
        System.out.println(pb);  
        ps.deletePerson(1);  
        pb = ps.queryPerson(1);  
        System.out.println(pb);  
    }  

package com.royzhou.jdbc;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestJdbcTemplate {
 public static void main(String[] args) {
  ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
  PersonService ps = (PersonService)ctx.getBean("personService");
  ps.addPerson(new PersonBean("royzhou"));
  PersonBean pb = ps.queryPerson(1);
  System.out.println(pb);
  pb.setName("haha");
  ps.updatePerson(pb);
  pb = ps.queryPerson(1);
  System.out.println(pb);
  ps.deletePerson(1);
  pb = ps.queryPerson(1);
  System.out.println(pb);
 }
}


上面代码先插入一条记录,然后修改,之后删除,运行之后出现异常,异常信息:
EmptyResultDataAccessException: Incorrect result size: expected 1, actual 0

难道Spring的queryForObject在查找不到记录的时候会抛出异常,看了一下Spring的源代码 发现确实如此:
Java代码
public Object queryForObject(String sql, Object[] args, int[] argTypes, RowMapper rowMapper) throws DataAccessException {  
        List results = (List) query(sql, args, argTypes, new RowMapperResultSetExtractor(rowMapper, 1));  
        return DataAccessUtils.requiredUniqueResult(results);  
    }  
 
    public Object queryForObject(String sql, Object[] args, RowMapper rowMapper) throws DataAccessException {  
        List results = (List) query(sql, args, new RowMapperResultSetExtractor(rowMapper, 1));  
        return DataAccessUtils.requiredUniqueResult(results);  
    }  
 
    public Object queryForObject(String sql, RowMapper rowMapper) throws DataAccessException {  
        List results = query(sql, rowMapper);  
        return DataAccessUtils.requiredUniqueResult(results);  
    }  
 
    public static Object requiredUniqueResult(Collection results) throws IncorrectResultSizeDataAccessException {  
        int size = (results != null ? results.size() : 0);  
        if (size == 0) {  
            throw new EmptyResultDataAccessException(1); // 问题在这里  
        }  
        if (!CollectionUtils.hasUniqueObject(results)) {  
            throw new IncorrectResultSizeDataAccessException(1, size);  
        }  
        return results.iterator().next();  
    } 

public Object queryForObject(String sql, Object[] args, int[] argTypes, RowMapper rowMapper) throws DataAccessException {
  List results = (List) query(sql, args, argTypes, new RowMapperResultSetExtractor(rowMapper, 1));
  return DataAccessUtils.requiredUniqueResult(results);
 }

 public Object queryForObject(String sql, Object[] args, RowMapper rowMapper) throws DataAccessException {
  List results = (List) query(sql, args, new RowMapperResultSetExtractor(rowMapper, 1));
  return DataAccessUtils.requiredUniqueResult(results);
 }

 public Object queryForObject(String sql, RowMapper rowMapper) throws DataAccessException {
  List results = query(sql, rowMapper);
  return DataAccessUtils.requiredUniqueResult(results);
 }

 public static Object requiredUniqueResult(Collection results) throws IncorrectResultSizeDataAccessException {
  int size = (results != null ? results.size() : 0);
  if (size == 0) {
   throw new EmptyResultDataAccessException(1); // 问题在这里
  }
  if (!CollectionUtils.hasUniqueObject(results)) {
      throw new IncorrectResultSizeDataAccessException(1, size);
  }
  return results.iterator().next();
 }


发现当查找不到记录是,requiredUniqueResult方法做了判断,抛出异常, 想不明白为什么Spring要在这里做这样的判断,为啥不返回null????

重新修改PersonServiceImple类,把queryPerson方法改为使用列表查询的方式再去根据index取
PersonServiceImpl.java
Java代码
package com.royzhou.jdbc;  
 
import java.util.List;  
 
import javax.sql.DataSource;  
import java.sql.Types;  
 
import org.springframework.jdbc.core.JdbcTemplate;  
 
public class PersonServiceImpl implements PersonService {  
 
    private JdbcTemplate jdbcTemplate;  
      
    /** 
     * 通过Spring容器注入datasource 
     * 实例化JdbcTemplate,该类为主要操作数据库的类 
     * @param ds 
     */ 
    public void setDataSource(DataSource ds) {  
        this.jdbcTemplate = new JdbcTemplate(ds);  
    }  
      
    public void addPerson(PersonBean person) {  
        /** 
         * 第一个参数为执行sql 
         * 第二个参数为参数数据 
         * 第三个参数为参数类型 
         */ 
        jdbcTemplate.update("insert into person values(null,?)", new Object[]{person.getName()}, new int[]{Types.VARCHAR});  
    }  
 
    public void deletePerson(int id) {  
        jdbcTemplate.update("delete from person where id = ?", new Object[]{id}, new int[]{Types.INTEGER});  
    }  
 
    @SuppressWarnings("unchecked")  
    public PersonBean queryPerson(int id) {  
        /** 
         * new PersonRowMapper()是一个实现RowMapper接口的类, 
         * 执行回调,实现mapRow()方法将rs对象转换成PersonBean对象返回 
         */ 
        List<PersonBean> pbs = (List<PersonBean>)jdbcTemplate.query("select id,name from person where id = ?", new Object[]{id}, new PersonRowMapper());  
        PersonBean pb = null;  
        if(pbs.size()>0) {  
            pb = pbs.get(0);  
        }  
        return pb;  
    }  
 
    @SuppressWarnings("unchecked")  
    public List<PersonBean> queryPersons() {  
        List<PersonBean> pbs = (List<PersonBean>) jdbcTemplate.query("select id,name from person", new PersonRowMapper());  
        return pbs;  
    }  
 
    public void updatePerson(PersonBean person) {  
        jdbcTemplate.update("update person set name = ? where id = ?", new Object[]{person.getName(), person.getId()}, new int[]{Types.VARCHAR, Types.INTEGER});  
    }  

package com.royzhou.jdbc;

import java.util.List;

import javax.sql.DataSource;
import java.sql.Types;

import org.springframework.jdbc.core.JdbcTemplate;

public class PersonServiceImpl implements PersonService {

 private JdbcTemplate jdbcTemplate;
 
 /**
  * 通过Spring容器注入datasource
  * 实例化JdbcTemplate,该类为主要操作数据库的类
  * @param ds
  */
 public void setDataSource(DataSource ds) {
  this.jdbcTemplate = new JdbcTemplate(ds);
 }
 
 public void addPerson(PersonBean person) {
  /**
   * 第一个参数为执行sql
   * 第二个参数为参数数据
   * 第三个参数为参数类型
   */
  jdbcTemplate.update("insert into person values(null,?)", new Object[]{person.getName()}, new int[]{Types.VARCHAR});
 }

 public void deletePerson(int id) {
  jdbcTemplate.update("delete from person where id = ?", new Object[]{id}, new int[]{Types.INTEGER});
 }

 @SuppressWarnings("unchecked")
 public PersonBean queryPerson(int id) {
  /**
   * new PersonRowMapper()是一个实现RowMapper接口的类,
   * 执行回调,实现mapRow()方法将rs对象转换成PersonBean对象返回
   */
  List<PersonBean> pbs = (List<PersonBean>)jdbcTemplate.query("select id,name from person where id = ?", new Object[]{id}, new PersonRowMapper());
  PersonBean pb = null;
  if(pbs.size()>0) {
   pb = pbs.get(0);
  }
  return pb;
 }

 @SuppressWarnings("unchecked")
 public List<PersonBean> queryPersons() {
  List<PersonBean> pbs = (List<PersonBean>) jdbcTemplate.query("select id,name from person", new PersonRowMapper());
  return pbs;
 }

 public void updatePerson(PersonBean person) {
  jdbcTemplate.update("update person set name = ? where id = ?", new Object[]{person.getName(), person.getId()}, new int[]{Types.VARCHAR, Types.INTEGER});
 }
}


再次运行测试类,输出:
1:royzhou
1:haha
null

得到预期的结果.

从上面代码可以看出,使用Spring提供的JDBCTemplate类很大程度减少了我们的代码量,
比起以前我们写JDBC操作,需要先获取Connection,然后是PreparedStatement,再到Result,
使用Spring JDBCTemplate写出来的代码看起来更加简洁,开发效率也比较快.

在数据库的操作中,事务是一个重要的概念,举个例子:

大概每个人都有转账的经历。当我们从A帐户向B帐户转100元后,银行的系统会从A帐户上扣除100而在B帐户上加100,这是一般的正常现象。
但是一旦系统出错了怎么办呢,这里我们假设可能会发生两种情况:
(1)A帐户上少了100元,但是B帐户却没有多100元。
(2)B帐户多了100元钱,但是A帐户上却没有被扣钱。
这种错误一旦发生就等于出了大事,那么再假如一下,你要转账的是1亿呢?
所以上面的两种情况分别是你和银行不愿意看到的,因为谁都不希望出错。那么有没有什么方法保证一旦A帐户上没有被扣钱而B帐户上也没有被加钱;
或者A帐户扣了100元而B帐户准确无误的加上100元呢。也就是说要么转账顺利的成功进行,要么不转账呢?可以,这就是数据库事务机制所要起到的作用和做的事情。

Spring对事务的管理有丰富的支持,Spring提供了编程式配置事务和声明式配置事务:

声明式事务有以下两种方式
一种是使用Annotation注解的方式(官方推荐)
一种是基于Xml的方式

采用任何一种方式我们都需要在我们的bean.xml中添加事务支持:
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
    xmlns:aop="http://www.springframework.org/schema/aop
    xmlns:tx="http://www.springframework.org/schema/tx
    xsi:schemaLocation="http://www.springframework.org/schema/beans  
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd  
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd  
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 
 
    <context:property-placeholder location="classpath:jdbc.properties" /> 
    <bean id="dataSource" 
        class="org.apache.commons.dbcp.BasicDataSource" 
        destroy-method="close"> 
        <property name="driverClassName" value="${driverClassName}" /> 
        <property name="url" value="${url}" /> 
        <property name="username" value="${username}" /> 
        <property name="password" value="${password}" /> 
        <!-- 连接池启动时的初始值 --> 
        <property name="initialSize" value="${initialSize}" /> 
        <!-- 连接池的最大值 --> 
        <property name="maxActive" value="${maxActive}" /> 
        <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 --> 
        <property name="maxIdle" value="${maxIdle}" /> 
        <!--  最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 --> 
        <property name="minIdle" value="${minIdle}" /> 
    </bean> 
 
    <bean id="personService" 
        class="com.royzhou.jdbc.PersonServiceImpl"> 
        <property name="dataSource" ref="dataSource"></property> 
    </bean> 
      
    <bean id="txManager" 
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
        <property name="dataSource" ref="dataSource" /> 
    </bean> 
      
    <tx:annotation-driven transaction-manager="txManager" />   
</beans> 

<?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"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

 <context:property-placeholder location="classpath:jdbc.properties" />
 <bean id="dataSource"
  class="org.apache.commons.dbcp.BasicDataSource"
  destroy-method="close">
  <property name="driverClassName" value="${driverClassName}" />
  <property name="url" value="${url}" />
  <property name="username" value="${username}" />
  <property name="password" value="${password}" />
  <!-- 连接池启动时的初始值 -->
  <property name="initialSize" value="${initialSize}" />
  <!-- 连接池的最大值 -->
  <property name="maxActive" value="${maxActive}" />
  <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
  <property name="maxIdle" value="${maxIdle}" />
  <!--  最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->
  <property name="minIdle" value="${minIdle}" />
 </bean>

 <bean id="personService"
  class="com.royzhou.jdbc.PersonServiceImpl">
  <property name="dataSource" ref="dataSource"></property>
 </bean>
 
 <bean id="txManager"
  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource" />
 </bean>
 
 <tx:annotation-driven transaction-manager="txManager" />
</beans>


<tx:annotation-driven transaction-manager="txManager" />  这句话的作用是注册事务注解处理器
定义好配置文件后我们只需要在我们的类上加上注解@Transactional,就可以指定这个类需要受Spring的事务管理
默认Spring为每个方法开启一个事务,如果方法发生运行期错误unchecked(RuntimeException),事务会进行回滚
如果发生checked Exception,事务不进行回滚.

例如在下面的例子中,我们为PersonServiceImpl添加事务支持.

Java代码
package com.royzhou.jdbc;  
 
import java.util.List;  
 
import javax.sql.DataSource;  
import java.sql.Types;  
 
import org.springframework.jdbc.core.JdbcTemplate;  
import org.springframework.transaction.annotation.Transactional;  
 
@Transactional 
public class PersonServiceImpl implements PersonService {  
 
    private JdbcTemplate jdbcTemplate;  
      
    /** 
     * 通过Spring容器注入datasource 
     * 实例化JdbcTemplate,该类为主要操作数据库的类 
     * @param ds 
     */ 
    public void setDataSource(DataSource ds) {  
        this.jdbcTemplate = new JdbcTemplate(ds);  
    }  
      
    public void addPerson(PersonBean person) {  
        /** 
         * 第一个参数为执行sql 
         * 第二个参数为参数数据 
         * 第三个参数为参数类型 
         */ 
        jdbcTemplate.update("insert into person values(null,?)", new Object[]{person.getName()}, new int[]{Types.VARCHAR});  
        throw new RuntimeException("运行期例外");  
    }  
 
    public void deletePerson(int id) {  
        jdbcTemplate.update("delete from person where id = ?", new Object[]{id}, new int[]{Types.INTEGER});  
    }  
 
    @SuppressWarnings("unchecked")  
    public PersonBean queryPerson(int id) {  
        /** 
         * new PersonRowMapper()是一个实现RowMapper接口的类, 
         * 执行回调,实现mapRow()方法将rs对象转换成PersonBean对象返回 
         */ 
        List<PersonBean> pbs = (List<PersonBean>)jdbcTemplate.query("select id,name from person where id = ?", new Object[]{id}, new PersonRowMapper());  
        PersonBean pb = null;  
        if(pbs.size()>0) {  
            pb = pbs.get(0);  
        }  
        return pb;  
    }  
 
    @SuppressWarnings("unchecked")  
    public List<PersonBean> queryPersons() {  
        List<PersonBean> pbs = (List<PersonBean>) jdbcTemplate.query("select id,name from person", new PersonRowMapper());  
        return pbs;  
    }  
 
    public void updatePerson(PersonBean person) {  
        jdbcTemplate.update("update person set name = ? where id = ?", new Object[]{person.getName(), person.getId()}, new int[]{Types.VARCHAR, Types.INTEGER});  
    }  

package com.royzhou.jdbc;

import java.util.List;

import javax.sql.DataSource;
import java.sql.Types;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;

@Transactional
public class PersonServiceImpl implements PersonService {

 private JdbcTemplate jdbcTemplate;
 
 /**
  * 通过Spring容器注入datasource
  * 实例化JdbcTemplate,该类为主要操作数据库的类
  * @param ds
  */
 public void setDataSource(DataSource ds) {
  this.jdbcTemplate = new JdbcTemplate(ds);
 }
 
 public void addPerson(PersonBean person) {
  /**
   * 第一个参数为执行sql
   * 第二个参数为参数数据
   * 第三个参数为参数类型
   */
  jdbcTemplate.update("insert into person values(null,?)", new Object[]{person.getName()}, new int[]{Types.VARCHAR});
  throw new RuntimeException("运行期例外");
 }

 public void deletePerson(int id) {
  jdbcTemplate.update("delete from person where id = ?", new Object[]{id}, new int[]{Types.INTEGER});
 }

 @SuppressWarnings("unchecked")
 public PersonBean queryPerson(int id) {
  /**
   * new PersonRowMapper()是一个实现RowMapper接口的类,
   * 执行回调,实现mapRow()方法将rs对象转换成PersonBean对象返回
   */
  List<PersonBean> pbs = (List<PersonBean>)jdbcTemplate.query("select id,name from person where id = ?", new Object[]{id}, new PersonRowMapper());
  PersonBean pb = null;
  if(pbs.size()>0) {
   pb = pbs.get(0);
  }
  return pb;
 }

 @SuppressWarnings("unchecked")
 public List<PersonBean> queryPersons() {
  List<PersonBean> pbs = (List<PersonBean>) jdbcTemplate.query("select id,name from person", new PersonRowMapper());
  return pbs;
 }

 public void updatePerson(PersonBean person) {
  jdbcTemplate.update("update person set name = ? where id = ?", new Object[]{person.getName(), person.getId()}, new int[]{Types.VARCHAR, Types.INTEGER});
 }
}


在addPerson方法中我们抛出了一个运行期例外,以此来检查Spring的事务管理.

编写测试类运行:
Java代码
package com.royzhou.jdbc;  
 
import org.springframework.context.ApplicationContext;  
import org.springframework.context.support.ClassPathXmlApplicationContext;  
 
public class TestJdbcTemplate {  
    public static void main(String[] args) {  
        ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");  
        PersonService ps = (PersonService)ctx.getBean("personService");  
        ps.addPerson(new PersonBean("royzhou"));  
    }  

package com.royzhou.jdbc;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestJdbcTemplate {
 public static void main(String[] args) {
  ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
  PersonService ps = (PersonService)ctx.getBean("personService");
  ps.addPerson(new PersonBean("royzhou"));
 }
}

运行测试类,后台输出异常:java.lang.RuntimeException: 运行期例外
查看数据库发现数据没有插入,说明事务进行了回滚.

再次测试修改为抛出checked Exception
Java代码
package com.royzhou.jdbc;  
 
import java.util.List;  
 
import javax.sql.DataSource;  
import java.sql.Types;  
 
import org.springframework.jdbc.core.JdbcTemplate;  
import org.springframework.transaction.annotation.Transactional;  
 
@Transactional 
public class PersonServiceImpl implements PersonService {  
 
    private JdbcTemplate jdbcTemplate;  
      
    /** 
     * 通过Spring容器注入datasource 
     * 实例化JdbcTemplate,该类为主要操作数据库的类 
     * @param ds 
     */ 
    public void setDataSource(DataSource ds) {  
        this.jdbcTemplate = new JdbcTemplate(ds);  
    }  
      
    public void addPerson(PersonBean person) throws Exception {  
        /** 
         * 第一个参数为执行sql 
         * 第二个参数为参数数据 
         * 第三个参数为参数类型 
         */ 
        jdbcTemplate.update("insert into person values(null,?)", new Object[]{person.getName()}, new int[]{Types.VARCHAR});  
        throw new Exception("checked 例外");  
    }  
 
    public void deletePerson(int id) {  
        jdbcTemplate.update("delete from person where id = ?", new Object[]{id}, new int[]{Types.INTEGER});  
    }  
 
    @SuppressWarnings("unchecked")  
    public PersonBean queryPerson(int id) {  
        /** 
         * new PersonRowMapper()是一个实现RowMapper接口的类, 
         * 执行回调,实现mapRow()方法将rs对象转换成PersonBean对象返回 
         */ 
        List<PersonBean> pbs = (List<PersonBean>)jdbcTemplate.query("select id,name from person where id = ?", new Object[]{id}, new PersonRowMapper());  
        PersonBean pb = null;  
        if(pbs.size()>0) {  
            pb = pbs.get(0);  
        }  
        return pb;  
    }  
 
    @SuppressWarnings("unchecked")  
    public List<PersonBean> queryPersons() {  
        List<PersonBean> pbs = (List<PersonBean>) jdbcTemplate.query("select id,name from person", new PersonRowMapper());  
        return pbs;  
    }  
 
    public void updatePerson(PersonBean person) {  
        jdbcTemplate.update("update person set name = ? where id = ?", new Object[]{person.getName(), person.getId()}, new int[]{Types.VARCHAR, Types.INTEGER});  
    }  

package com.royzhou.jdbc;

import java.util.List;

import javax.sql.DataSource;
import java.sql.Types;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;

@Transactional
public class PersonServiceImpl implements PersonService {

 private JdbcTemplate jdbcTemplate;
 
 /**
  * 通过Spring容器注入datasource
  * 实例化JdbcTemplate,该类为主要操作数据库的类
  * @param ds
  */
 public void setDataSource(DataSource ds) {
  this.jdbcTemplate = new JdbcTemplate(ds);
 }
 
 public void addPerson(PersonBean person) throws Exception {
  /**
   * 第一个参数为执行sql
   * 第二个参数为参数数据
   * 第三个参数为参数类型
   */
  jdbcTemplate.update("insert into person values(null,?)", new Object[]{person.getName()}, new int[]{Types.VARCHAR});
  throw new Exception("checked 例外");
 }

 public void deletePerson(int id) {
  jdbcTemplate.update("delete from person where id = ?", new Object[]{id}, new int[]{Types.INTEGER});
 }

 @SuppressWarnings("unchecked")
 public PersonBean queryPerson(int id) {
  /**
   * new PersonRowMapper()是一个实现RowMapper接口的类,
   * 执行回调,实现mapRow()方法将rs对象转换成PersonBean对象返回
   */
  List<PersonBean> pbs = (List<PersonBean>)jdbcTemplate.query("select id,name from person where id = ?", new Object[]{id}, new PersonRowMapper());
  PersonBean pb = null;
  if(pbs.size()>0) {
   pb = pbs.get(0);
  }
  return pb;
 }

 @SuppressWarnings("unchecked")
 public List<PersonBean> queryPersons() {
  List<PersonBean> pbs = (List<PersonBean>) jdbcTemplate.query("select id,name from person", new PersonRowMapper());
  return pbs;
 }

 public void updatePerson(PersonBean person) {
  jdbcTemplate.update("update person set name = ? where id = ?", new Object[]{person.getName(), person.getId()}, new int[]{Types.VARCHAR, Types.INTEGER});
 }
}

后台输出异常:java.lang.Exception: checked 例外
查看数据库发现数据插入,说明事务没有进行了回滚.

说明了Spring的事务支持默认只对运行期异常(RuntimeException)进行回滚,这里可能有个疑问,我们执行sql操作的时候会发生sql异常,不属于运行期异常,那Spring是怎么进行事务回滚的呢 ????
查看了一下JdbcTemplate的源代码发现,JdbcTemplate的处理方法如下:
Java代码
public int[] batchUpdate(String sql, final BatchPreparedStatementSetter pss) throws DataAccessException {  
    if (logger.isDebugEnabled()) {  
        logger.debug("Executing SQL batch update [" + sql + "]");  
    }  
    return (int[]) execute(sql, new PreparedStatementCallback() {  
        public Object doInPreparedStatement(PreparedStatement ps) throws SQLException {  
            try {  
                int batchSize = pss.getBatchSize();  
                if (JdbcUtils.supportsBatchUpdates(ps.getConnection())) {  
                    for (int i = 0; i < batchSize; i++) {  
                        pss.setValues(ps, i);  
                        ps.addBatch();  
                    }  
                    return ps.executeBatch();  
                }  
                else {  
                    int[] rowsAffected = new int[batchSize];  
                    for (int i = 0; i < batchSize; i++) {  
                        pss.setValues(ps, i);  
                        rowsAffected[i] = ps.executeUpdate();  
                    }  
                    return rowsAffected;  
                }  
            }  
            finally {  
                if (pss instanceof ParameterDisposer) {  
                    ((ParameterDisposer) pss).cleanupParameters();  
                }  
            }  
        }  
    });  

 public int[] batchUpdate(String sql, final BatchPreparedStatementSetter pss) throws DataAccessException {
  if (logger.isDebugEnabled()) {
   logger.debug("Executing SQL batch update [" + sql + "]");
  }
  return (int[]) execute(sql, new PreparedStatementCallback() {
   public Object doInPreparedStatement(PreparedStatement ps) throws SQLException {
    try {
     int batchSize = pss.getBatchSize();
     if (JdbcUtils.supportsBatchUpdates(ps.getConnection())) {
      for (int i = 0; i < batchSize; i++) {
       pss.setValues(ps, i);
       ps.addBatch();
      }
      return ps.executeBatch();
     }
     else {
      int[] rowsAffected = new int[batchSize];
      for (int i = 0; i < batchSize; i++) {
       pss.setValues(ps, i);
       rowsAffected[i] = ps.executeUpdate();
      }
      return rowsAffected;
     }
    }
    finally {
     if (pss instanceof ParameterDisposer) {
      ((ParameterDisposer) pss).cleanupParameters();
     }
    }
   }
  });
 }


在代码中捕获了SQLException然后抛出一个org.springframework.dao.DataAcceddException,该异常继承自org.springframework.core.NestedRuntimeException,NestedRuntimeException
是一个继承自RuntimeException的抽象类,Spring jdbcTemplate处理发生异常处理后抛出来得异常基本上都会继承NestedRuntimeException,看完之后才确信了Spring默认只对RuntimeException进行回滚

当然我们可可以修改Spring的默认配置,当发生RuntimeException我们也可以不让他进行事务回滚
只需要加上一个@Transactional(noRollbackFor=RuntimeException.class)
注意@Transactional只能针对public属性范围内的方法添加
Java代码
package com.royzhou.jdbc;  
 
import java.util.List;  
 
import javax.sql.DataSource;  
import java.sql.Types;  
 
import org.springframework.jdbc.core.JdbcTemplate;  
import org.springframework.transaction.annotation.Transactional;  
 
@Transactional 
public class PersonServiceImpl implements PersonService {  
 
    private JdbcTemplate jdbcTemplate;  
      
    /** 
     * 通过Spring容器注入datasource 
     * 实例化JdbcTemplate,该类为主要操作数据库的类 
     * @param ds 
     */ 
    public void setDataSource(DataSource ds) {  
        this.jdbcTemplate = new JdbcTemplate(ds);  
    }  
      
    @Transactional(noRollbackFor=RuntimeException.class)  
    public void addPerson(PersonBean person) {  
        /** 
         * 第一个参数为执行sql 
         * 第二个参数为参数数据 
         * 第三个参数为参数类型 
         */ 
        jdbcTemplate.update("insert into person values(null,?)", new Object[]{person.getName()}, new int[]{Types.VARCHAR});  
        throw new RuntimeException("运行期例外");  
    }  
 
    public void deletePerson(int id) {  
        jdbcTemplate.update("delete from person where id = ?", new Object[]{id}, new int[]{Types.INTEGER});  
    }  
 
    @SuppressWarnings("unchecked")  
    public PersonBean queryPerson(int id) {  
        /** 
         * new PersonRowMapper()是一个实现RowMapper接口的类, 
         * 执行回调,实现mapRow()方法将rs对象转换成PersonBean对象返回 
         */ 
        List<PersonBean> pbs = (List<PersonBean>)jdbcTemplate.query("select id,name from person where id = ?", new Object[]{id}, new PersonRowMapper());  
        PersonBean pb = null;  
        if(pbs.size()>0) {  
            pb = pbs.get(0);  
        }  
        return pb;  
    }  
 
    @SuppressWarnings("unchecked")  
    public List<PersonBean> queryPersons() {  
        List<PersonBean> pbs = (List<PersonBean>) jdbcTemplate.query("select id,name from person", new PersonRowMapper());  
        return pbs;  
    }  
 
    public void updatePerson(PersonBean person) {  
        jdbcTemplate.update("update person set name = ? where id = ?", new Object[]{person.getName(), person.getId()}, new int[]{Types.VARCHAR, Types.INTEGER});  
    }  

package com.royzhou.jdbc;

import java.util.List;

import javax.sql.DataSource;
import java.sql.Types;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;

@Transactional
public class PersonServiceImpl implements PersonService {

 private JdbcTemplate jdbcTemplate;
 
 /**
  * 通过Spring容器注入datasource
  * 实例化JdbcTemplate,该类为主要操作数据库的类
  * @param ds
  */
 public void setDataSource(DataSource ds) {
  this.jdbcTemplate = new JdbcTemplate(ds);
 }
 
 @Transactional(noRollbackFor=RuntimeException.class)
 public void addPerson(PersonBean person) {
  /**
   * 第一个参数为执行sql
   * 第二个参数为参数数据
   * 第三个参数为参数类型
   */
  jdbcTemplate.update("insert into person values(null,?)", new Object[]{person.getName()}, new int[]{Types.VARCHAR});
  throw new RuntimeException("运行期例外");
 }

 public void deletePerson(int id) {
  jdbcTemplate.update("delete from person where id = ?", new Object[]{id}, new int[]{Types.INTEGER});
 }

 @SuppressWarnings("unchecked")
 public PersonBean queryPerson(int id) {
  /**
   * new PersonRowMapper()是一个实现RowMapper接口的类,
   * 执行回调,实现mapRow()方法将rs对象转换成PersonBean对象返回
   */
  List<PersonBean> pbs = (List<PersonBean>)jdbcTemplate.query("select id,name from person where id = ?", new Object[]{id}, new PersonRowMapper());
  PersonBean pb = null;
  if(pbs.size()>0) {
   pb = pbs.get(0);
  }
  return pb;
 }

 @SuppressWarnings("unchecked")
 public List<PersonBean> queryPersons() {
  List<PersonBean> pbs = (List<PersonBean>) jdbcTemplate.query("select id,name from person", new PersonRowMapper());
  return pbs;
 }

 public void updatePerson(PersonBean person) {
  jdbcTemplate.update("update person set name = ? where id = ?", new Object[]{person.getName(), person.getId()}, new int[]{Types.VARCHAR, Types.INTEGER});
 }
}


运行测试类:
Java代码
package com.royzhou.jdbc;  
 
import org.springframework.context.ApplicationContext;  
import org.springframework.context.support.ClassPathXmlApplicationContext;  
 
public class TestJdbcTemplate {  
    public static void main(String[] args) {  
        ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");  
        PersonService ps = (PersonService)ctx.getBean("personService");  
        ps.addPerson(new PersonBean("royzhou"));  
    }  

package com.royzhou.jdbc;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestJdbcTemplate {
 public static void main(String[] args) {
  ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
  PersonService ps = (PersonService)ctx.getBean("personService");
  ps.addPerson(new PersonBean("royzhou"));
 }
}


后台抛出异常,查看数据库,记录插入进去了,说明我们配置事务不对RuntimeException回滚生效了.
既然可以配置不对RuntimeException回滚,那我们也可以配置对Exception进行回滚,主要用到的是
@Transactional(rollbackFor=Exception.class)

对于一些查询工作,因为不需要配置事务支持,我们配置事务的传播属性:
@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)

readOnly=true表示事务中不允许存在更新操作.

关于事务的传播属性有下面几种配置:
REQUIRED:业务方法需要在一个事务中运行,如果方法运行时,已经处于一个事务中,那么加入到该事务中,否则自己创建一个新的事务.(Spring默认的事务传播属性)
NOT_SUPPORTED:声明方法不需要事务,如果方法没有关联到一个事务,容器不会为它开启事务,如果方法在一个事务中被调用,该事务被挂起,在方法调用结束后,原先的事务便会恢复执行
REQUIRESNEW:不管是否存在事务,业务方法总会为自己发起一个新的事务,如果方法运行时已经存在一个事务,则该事务会被挂起,新的事务被创建,知道方法执行结束,新事务才结束,原先的事务才恢复执行.
MANDATORY:指定业务方法只能在一个已经存在的事务中执行,业务方法不能自己发起事务,如果业务方法没有在事务的环境下调用,则容器会抛出异常
SUPPORTS:如果业务方法在事务中被调用,则成为事务中的一部分,如果没有在事务中调用,则在没有事务的环境下执行
NEVER:指定业务方法绝对不能在事务范围内运行,否则会抛出异常.
NESTED:如果业务方法运行时已经存在一个事务,则新建一个嵌套的事务,该事务可以有多个回滚点,如果没有事务,则按REQUIRED属性执行. 注意:业务方法内部事务的回滚不会对外部事务造成影响,但是外部事务的回滚会影响内部事务


关于使用注解的方式来配置事务就到这里,
我们还可以使用另外一种方式实现事务的管理,通过xml文件的配置,主要通过AOP技术实现:

首先把我们的业务类的注解去掉:
Java代码
package com.royzhou.jdbc;  
 
import java.util.List;  
 
import javax.sql.DataSource;  
import java.sql.Types;  
 
import org.springframework.jdbc.core.JdbcTemplate;  
 
public class PersonServiceImpl implements PersonService {  
 
    private JdbcTemplate jdbcTemplate;  
      
    /** 
     * 通过Spring容器注入datasource 
     * 实例化JdbcTemplate,该类为主要操作数据库的类 
     * @param ds 
     */ 
    public void setDataSource(DataSource ds) {  
        this.jdbcTemplate = new JdbcTemplate(ds);  
    }  
      
    public void addPerson(PersonBean person) {  
        /** 
         * 第一个参数为执行sql 
         * 第二个参数为参数数据 
         * 第三个参数为参数类型 
         */ 
        jdbcTemplate.update("insert into person values(null,?)", new Object[]{person.getName()}, new int[]{Types.VARCHAR});  
        throw new RuntimeException("运行期例外");  
    }  
 
    public void deletePerson(int id) {  
        jdbcTemplate.update("delete from person where id = ?", new Object[]{id}, new int[]{Types.INTEGER});  
    }  
      
    @SuppressWarnings("unchecked")  
    public PersonBean queryPerson(int id) {  
        /** 
         * new PersonRowMapper()是一个实现RowMapper接口的类, 
         * 执行回调,实现mapRow()方法将rs对象转换成PersonBean对象返回 
         */ 
        List<PersonBean> pbs = (List<PersonBean>)jdbcTemplate.query("select id,name from person where id = ?", new Object[]{id}, new PersonRowMapper());  
        PersonBean pb = null;  
        if(pbs.size()>0) {  
            pb = pbs.get(0);  
        }  
        return pb;  
    }  
 
    @SuppressWarnings("unchecked")  
    public List<PersonBean> queryPersons() {  
        List<PersonBean> pbs = (List<PersonBean>) jdbcTemplate.query("select id,name from person", new PersonRowMapper());  
        return pbs;  
    }  
 
    public void updatePerson(PersonBean person) {  
        jdbcTemplate.update("update person set name = ? where id = ?", new Object[]{person.getName(), person.getId()}, new int[]{Types.VARCHAR, Types.INTEGER});  
    }  

package com.royzhou.jdbc;

import java.util.List;

import javax.sql.DataSource;
import java.sql.Types;

import org.springframework.jdbc.core.JdbcTemplate;

public class PersonServiceImpl implements PersonService {

 private JdbcTemplate jdbcTemplate;
 
 /**
  * 通过Spring容器注入datasource
  * 实例化JdbcTemplate,该类为主要操作数据库的类
  * @param ds
  */
 public void setDataSource(DataSource ds) {
  this.jdbcTemplate = new JdbcTemplate(ds);
 }
 
 public void addPerson(PersonBean person) {
  /**
   * 第一个参数为执行sql
   * 第二个参数为参数数据
   * 第三个参数为参数类型
   */
  jdbcTemplate.update("insert into person values(null,?)", new Object[]{person.getName()}, new int[]{Types.VARCHAR});
  throw new RuntimeException("运行期例外");
 }

 public void deletePerson(int id) {
  jdbcTemplate.update("delete from person where id = ?", new Object[]{id}, new int[]{Types.INTEGER});
 }
 
 @SuppressWarnings("unchecked")
 public PersonBean queryPerson(int id) {
  /**
   * new PersonRowMapper()是一个实现RowMapper接口的类,
   * 执行回调,实现mapRow()方法将rs对象转换成PersonBean对象返回
   */
  List<PersonBean> pbs = (List<PersonBean>)jdbcTemplate.query("select id,name from person where id = ?", new Object[]{id}, new PersonRowMapper());
  PersonBean pb = null;
  if(pbs.size()>0) {
   pb = pbs.get(0);
  }
  return pb;
 }

 @SuppressWarnings("unchecked")
 public List<PersonBean> queryPersons() {
  List<PersonBean> pbs = (List<PersonBean>) jdbcTemplate.query("select id,name from person", new PersonRowMapper());
  return pbs;
 }

 public void updatePerson(PersonBean person) {
  jdbcTemplate.update("update person set name = ? where id = ?", new Object[]{person.getName(), person.getId()}, new int[]{Types.VARCHAR, Types.INTEGER});
 }
}


然后我们需要在bean.xml文件中配置:
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
    xmlns:aop="http://www.springframework.org/schema/aop
    xmlns:tx="http://www.springframework.org/schema/tx
    xsi:schemaLocation="http://www.springframework.org/schema/beans  
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
           http://www.spri

评论

相关推荐

    Spring JDBC与事务管理

    javaEE 实验三 Spring JDBC与事务管理, 一、实验目的 1、掌握Spring JDBC的配置; 2、掌握JdbcTemplae类中增删改查方法的使用; 3、了解Spring事务管理的3个核心接口; 4、了解Spring事务管理的两种方式; 5、掌握...

    Spring JDBC常用Jar包

    Spring JDBC是Spring框架的一部分,主要用于简化Java数据库连接操作。它提供了一个抽象层,使得开发者能够以统一的方式处理各种数据库,而无需直接与JDBC API打交道,从而降低了代码的复杂性和错误率。在"Spring ...

    spring jdbc示例代码

    Spring JDBC是Spring框架的一部分,它提供了一种更高级的方式来处理传统的Java JDBC(Java Database Connectivity),以简化数据库操作。本示例代码将展示如何在Spring环境中使用JDBC进行数据的增删改查操作,并对比...

    spring jdbc.zip

    《Spring JDBC:Spring框架对JDBC的封装与实践》 Spring框架是Java开发中的一个核心组件,它极大地简化了企业级应用的开发工作。在Spring框架中,Spring JDBC(Java Database Connectivity)模块扮演着重要的角色,...

    最简单的用户登录与注册系统 spring mvc spring jdbc

    Spring MVC是Spring框架的一个模块,主要用于构建Web应用程序,而Spring JDBC则是Spring提供的用于简化数据库操作的工具。 【描述】"用spring4.0.5版本开发的,spring mvc,spring jdbc,最简单的用户登录,注册和...

    spring JDbc

    Spring JDBC是Spring框架的一个核心模块,它为Java数据库连接(JDBC)提供了一个高级抽象层,简化了数据库操作。在本实例中,我们将深入探讨Spring JDBC的使用,并以`SpringJdbcTemplate`为例来阐述其主要功能和优势...

    spring4 、 springmvc4.2、springjdbc

    Spring框架是Java开发中广泛应用的一个开源框架,它主要由Spring Core、Spring MVC和Spring JDBC等模块组成。在本文中,我们将深入探讨这三个核心模块以及它们的功能和整合方式。 首先,Spring Core是整个Spring...

    SpringMVC+SpringJDBC

    SpringMVC和SpringJDBC是Java开发中两个重要的框架,它们分别是Spring框架在Web层和数据访问层的应用。本文将详细介绍这两个组件的核心概念、工作原理以及如何整合使用,旨在帮助开发者更好地理解和应用。 **...

    Spring+Spring MVC+Spring JDBC+MySql实现简单登录注册

    在本项目中,我们主要利用Spring框架,包括其核心模块Spring、MVC模块Spring MVC以及数据访问/集成模块Spring JDBC,结合MySQL数据库来构建一个基础的登录注册系统。以下是这个项目涉及的关键技术点: 1. **Spring...

    spring jdbc相关包版本5.1.3

    Spring JDBC模块是Spring框架的一部分,它提供了对JDBC(Java Database Connectivity)的高级抽象,简化了数据库操作。在这个场景中,我们关注的是Spring JDBC的5.1.3版本。 **Spring JDBC 5.1.3 版本详解** ...

    spring JDBC所需jar包

    在Java开发中,Spring框架是不可或缺的一部分,尤其在处理数据访问层时,Spring JDBC提供了一种强大而灵活的方式来管理数据库连接。Spring JDBC模块是Spring框架的一部分,它简化了JDBC的使用,使得开发者可以更加...

    maven-springMVC-springJDBC-Demo

    【标题】"maven-springMVC-springJDBC-Demo"是一个综合性的项目示例,它演示了如何使用Maven、Spring MVC和Spring JDBC在Java Web开发中构建一个简单的应用。这个Demo旨在帮助开发者理解这三大技术的集成与协同工作...

    Spring JDBC应用实例讲解

    Spring JDBC是Spring框架中的一个核心模块,主要用于简化Java数据库编程。在本文中,我们将深入探讨Spring JDBC的应用实例,了解如何利用它来实现高效且灵活的数据访问。首先,我们需要理解Spring JDBC是如何通过...

    SpringJDBC训练素材.zip

    Spring JDBC是Spring框架的一部分,它提供了一种抽象层,使得开发者可以更方便地使用Java数据库连接(JDBC)进行数据库操作。Spring JDBC的核心是JdbcTemplate类,它简化了执行SQL语句的过程,减少了代码量,并提高...

    Spring事务管理和SpringJDBC思维导图

    本话题主要关注Spring的两个重要模块:事务管理和Spring JDBC。这些知识点对于任何使用Spring进行后端开发的程序员来说都是至关重要的。 首先,我们来深入理解Spring事务管理。事务是数据库操作的基本单元,它确保...

    Spring JDBC 增删改查

    Spring JDBC是Spring框架的一部分,它提供了一种抽象层,使得我们能够更方便地使用Java数据库连接(JDBC)来处理数据库操作,如增删改查(CRUD)。在这个主题下,我们将深入探讨Spring JDBC的核心概念、配置、以及...

    Spring mvc + Spring + Spring jdbc 整合 demo

    在本项目中,我们主要探讨的是如何将Spring MVC、Spring框架和Spring JDBC这三大核心组件进行整合,构建一个完整的Java Web应用程序。这个整合Demo旨在帮助开发者理解这些技术的协同工作方式,以及如何在实际开发中...

    Spring JDBC实现代码

    Spring JDBC模块是Spring框架的一部分,它简化了Java Database Connectivity (JDBC)的使用,使得数据库操作更加简单且易于管理。本篇文章将深入探讨如何使用Spring JDBC在Spring 2.5版本中与MySQL数据库进行交互,...

    SpringJDBC

    Spring JDBC是Spring框架的一个核心模块,它为Java开发者提供了便捷的方式来操作数据库。Spring JDBC通过抽象出数据库连接管理、事务处理以及结果集处理等繁琐工作,使得开发者可以专注于SQL语句和业务逻辑,而不必...

    SpringJDBC.rar_SpringJDBC_spring jdbc

    通过这个SpringJDBC.rar的案例,初学者可以学习到如何配置DataSource,如何创建JdbcTemplate实例,以及如何编写和执行SQL语句。同时,实践中还可以了解到如何将Spring JDBC整合到Spring Boot项目中,以及如何处理...

Global site tag (gtag.js) - Google Analytics