Spring JdbcTemplate 与 事务管理 学习(转)

也许不会看见 2010-09-28

Spring的JDBC框架能够承担资源管理和异常处理的工作,从而简化我们的JDBC代码,

让我们只需编写从数据库读写数据所必需的代码。Spring把数据访问的样板代码隐藏到模板类之下,

结合Spring的事务管理,可以大大简化我们的代码.

Spring提供了3个模板类:

JdbcTemplate:Spring里最基本的JDBC模板,利用JDBC和简单的索引参数查询提供对数据库的简单访问。

NamedParameterJdbcTemplate:能够在执行查询时把值绑定到SQL里的命名参数,而不是使用索引参数。

SimpleJdbcTemplate:利用Java5的特性,比如自动装箱、通用(generic)和可变参数列表来简化JDBC模板的使用。

具体使用哪个模板基本上取决于个人喜好。

使用Spring的JdbcTemplate来实现简单的增删改查,首先建立测试数据表person

createtableperson(

idintnotnullprimarykeyauto_increment,

namevarchar(20)notnull

)

导入依赖的jar包,由于测试中数据源使用的是dbcp数据源,需要以下jar包支持:

commons-logging.jar

commons-pool.jar

commons-dbcp.jar

同时还必须导入数据库驱动jar包:mysql-connector-java-3.1.8-bin.jar

建立实体bean

Person.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
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
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

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注入到我们的业务类中

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

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:Incorrectresultsize:expected1,actual0

难道Spring的queryForObject在查找不到记录的时候会抛出异常,看了一下Spring的源代码 发现确实如此:
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
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,

使用SpringJDBCTemplate写出来的代码看起来更加简洁,开发效率也比较快.

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

大概每个人都有转账的经历。当我们从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代码 Spring JdbcTemplate 与 事务管理 学习(转)
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xmlns:context="http://www.springframework.org/schema/context"  
  5.     xmlns:aop="http://www.springframework.org/schema/aop"  
  6.     xmlns:tx="http://www.springframework.org/schema/tx"  
  7.     xsi:schemaLocation="http://www.springframework.org/schema/beans   
  8.            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd   
  9.            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd   
  10.            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd   
  11.            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">  
  12.   
  13.     <context:property-placeholder location="classpath:jdbc.properties" color: #

相关推荐

Gbug00 / 0评论 2010-10-08