Spring JDBC
一、Spring JDBC简介
我们早期都有过直接使用JDBC访问数据库的经历,开发者需要编写获取数据库连接
,处理异常
,释放资源
,数据操作
等代码。即使很简单的数据库操作,都需要很繁琐的编写。Spring JDBC通过模板和回调机制大大降低了JDBC的繁琐程度,我们仅需编写那些必不可少的数据操作代码就可以完成操作。
二、Spring模板和回调机制
在直接使用JDBC时。我们需要处理获取连接,处理异常、释放资源等整个流程。Spring为支持的持久化技术提供了模板访问的方式,我们只需要提供具体的操作数据代码即可,可以大幅度提高开发效率。
Spring将相同的数据访问流程固定到模板类中,例如,获取连接、释放资源等等。将数据库操作中固定和变化的部分分开,同时保证模板类线程安全,以便多个线程共享同一模块实例。固定的部分在模板类中已经写好,变化的部分通过回调接口开放出来,用于具体的数据访问和结果处理操作。
Spring为各种支持的持久化技术都提供了简化操作的模板和回调。例如为传统的JDBC提供了JdbcTemplate模块类,为Hibernate提供了HibernateTemplate模板类等等很多。我们直接使用即可。
三、Spring JDBC入门例子
不论使用任何持久化技术,都必须拥有数据库连接。在Spring中,我们需要配置数据库连接池来获取连接。我们的代码中都统一使用c3p0连接池。
首先我们要先导包,我们需要导入spring的核心四个包
和jdbc包
和tx包(事务操作)
,然后还需要导入c3p0包
和数据库驱动
等。
我们创建一个数据库和数据表来进行演示
CREATE DATABASE springdb;
USE springdb;
CREATE TABLE USER(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50),
PASSWORD VARCHAR(50)
);
INSERT INTO USER(username,PASSWORD) VALUES('张三','123456');
我们来演示一下怎么使用JdbcTemplate
public class TestJdbc {
@Test
public void test() throws Exception{
//创建c3p0连接池,并设置相应的数据库参数
ComboPooledDataSource datasource=new ComboPooledDataSource();
datasource.setDriverClass("com.mysql.jdbc.Driver");
datasource.setJdbcUrl("jdbc:mysql://localhost:3306/springdb");
datasource.setUser("root");
datasource.setPassword("123456");
//创建JdbcTemplate对数据库进行操作
JdbcTemplate template=new JdbcTemplate(datasource);
String sql="insert into user(username,password) values(?,?)";
template.update(sql, "李四","456789");
}
}
四、详解JdbcTemplate
JdbcTemplate模板类几乎可以完成任何数据访问的操作,并且非常方便简介。我们上面的例子都是手动通过API 来创建连接池,来创建JdbcTemplate,我们完全可以使用我们学习的IoC来使用配置文件来替代那些操作,这也是我们所提倡的。
使用配置文件
我们在Dao中使用Jdbctemplate,JdbcTemplate直接在配置文件中配置好,直接在Dao中注入即可。
//我们先创建一个实体类
public class User {
private int id;
private String username;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", password=" + password + "]";
}
}
//创建Dao来对数据进行操作
public class UserDao {
//提供JdbcTemplate和set方法来进行注入
private JdbcTemplate template;
public void setTemplate(JdbcTemplate template) {
this.template = template;
}
//更新方法
public void update(User user){
String sql="update user set username=?,password=? where id=?";
Object []params={user.getUsername(),user.getPassword(),user.getId()};
template.update(sql, params);
}
}
<!--编写配置文件-->
<?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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置连接池-->
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/springdb"></property>
<property name="user" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<!--实例JdbcTemplate,并且通过dataSource属性注入连接池-->
<bean id="jdbctemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="datasource"></property>
</bean>
<!--实例化Dao,并注入JdbcTemplate-->
<bean id="userdao" class="com.spring.jdbc.UserDao">
<property name="template" ref="jdbctemplate"></property>
</bean>
</beans>
//我们来测试一下
public class TestJdbc {
@Test
public void test() throws Exception{
ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");
UserDao userdao=(UserDao) ac.getBean("userdao");
User user=new User();
user.setId(1);
user.setUsername("王五");
user.setPassword("888888");
userdao.update(user);
}
}
使用属性文件配置数据库信息
数据库的配置信息有可能需要经常改动,所以一般将数据库配置信息放在属性文件中。
//创建一个属性文件,名为jdbc.properties
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql://localhost:3306/springdb
user=root
password=123456
<!--引入属性文件,以${xxx}的方式引入属性-->
<context:property-placeholder location="jdbc.properties"/>
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${driverClass}"></property>
<property name="jdbcUrl" value="${jdbcUrl}"></property>
<property name="user" value="${user}"></property>
<property name="password" value="${password}"></property>
</bean>
JdbcDaoSupport
我们的Dao层使用JdbcTemplate都需要提供一个JdbcTemplate属性和set方法来进行注入,而Spring为我们提供了一个父类JdbcDaoSupport,已经帮我们做好了这些操作。
//我们的Dao继承JdbcDaoSupport
public class UserDao extends JdbcDaoSupport{
public void update(User user){
String sql="update user set username=?,password=? where id=?";
Object []params={user.getUsername(),user.getPassword(),user.getId()};
this.getJdbcTemplate().update(sql, params);
}
}
//更改配置文件
<?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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/springdb"></property>
<property name="user" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<!--只需要将连接池给它,父类会自动帮我们创建JdbcTemplate-->
<bean id="userdao" class="com.spring.jdbc.UserDao">
<property name="dataSource" ref="datasource"></property>
</bean>
</beans>
批量更改数据
如果需要一次性插入或更新多条记录,我们可以使用JdbcTemplate提供的批量操作的方法。
int[] batchUpdate(String []sql):多条不带参数的sql语句组成一个数组,该方法以批量方式执行这些sql语句,底层使用JDBC提供的批量操作的API。
int[] batchUpdate(String sql,BatchPreparedStatementSetter pss):使用本方法对带参sql语句进行多次数据更新操作,通过BatchPreparedStatementSetter回调接口进行批量参数的绑定工作。该接口定义了两个方法:
int getBatchSize():指定本批次的大小
void setValues(PreparedStatement ps,int i):为给定的PreparedStatement设置参数
//我们为我们的Dao添加一个添加班级的操作,一次性插入多个User
public void addClass(final List<User> l){
String sql="insert into user(username,password) values(?,?)";
//执行批量操作
template.batchUpdate(sql, new BatchPreparedStatementSetter() {
//绑定插入的参数
public void setValues(PreparedStatement ps, int index) throws SQLException {
User user=l.get(index);
ps.setString(1, user.getUsername());
ps.setString(2, user.getPassword());
}
public int getBatchSize() {
return l.size();
}
});
}
//我们来进行测试一下
public class TestJdbc {
@Test
public void test() throws Exception{
ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");
UserDao userdao=(UserDao) ac.getBean("userdao");
List<User> list=new ArrayList<User>();
User user1=new User();
user1.setUsername("孙悟空");
user1.setPassword("123");
User user2=new User();
user2.setUsername("猪八戒");
user2.setPassword("456");
list.add(user1);
list.add(user2);
userdao.addClass(list);
}
}
查询所有数据
//Spring提供了RowMapper<T>接口来处理结果集,有很多实现类,我们使用BeanPropertyRowMapper
public List<User> selectAll(){
String sql="select * from user";
return template.query(sql,BeanPropertyRowMapper.newInstance(User.class));
}
//我们测试一下
public class TestJdbc {
@Test
public void test() throws Exception{
ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");
UserDao userdao=(UserDao) ac.getBean("userdao");
List<User> list=userdao.selectAll();
for(User u:list){
System.out.println(u);
}
}
}
五、NamedParameterJdbcTemplate
在JdbcTemplate中,我们只能使用?占位符来声明sql语句参数,使用索引来绑定参数,如果我们uyao新增一个占位符,可能会导致很多问题。这种编程模式被认为是弱稳定的。
NamedParameterJdbcTemplate模板类支持命名参数绑定
的功能。
SqlParameterSource接口
用来提供参数 ,有两个实现类:
- BeanPropertySqlParameterSource:该类将JavaBean对象封装成参数,以便通过javaBean属性名和SQL语句中命名参数匹配的方式绑定参数。
- MapSqlParameterSource:该实现类内部通过一个Map存储参数。
//我们创建一个Dao类
public class StudentDao {
//提供NamedParameterJdbcTemplate,以便注入
private NamedParameterJdbcTemplate template;
public void setTemplate(NamedParameterJdbcTemplate template) {
this.template = template;
}
public void addStudent(User user){
//使用命名参数,格式是:javaBean属性名
String sql="insert into user(username,password) values(:username,:password)";
//提供参数
SqlParameterSource sps=new BeanPropertySqlParameterSource(user);
template.update(sql, sps);
}
}
<!--配置文件-->
<?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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:property-placeholder location="jdbc.properties"/>
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${driverClass}"></property>
<property name="jdbcUrl" value="${jdbcUrl}"></property>
<property name="user" value="${user}"></property>
<property name="password" value="${password}"></property>
</bean>
<bean id="template" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg ref="datasource"></constructor-arg>
</bean>
<bean id="studentdao" class="com.spring.jdbc.StudentDao">
<property name="template" ref="template"></property>
</bean>
</beans>
//我们测试一下
public class TestJdbc {
@Test
public void test() throws Exception{
ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");
StudentDao studentdao=(StudentDao) ac.getBean("studentdao");
User user=new User();
user.setUsername("天蓬元帅");
user.setPassword("123456");
studentdao.addStudent(user);
}
}
Spring在org.springframework.jdbc.object包中提供了若干个类,试图以更面向对象过的方式访问数据库,但从操作难易度和使用效果上看,我们看不到它的优势,基本算是很鸡肋的功能。Spring的Jdbc只要能用上述的一些基本操作即可,毕竟有许多专业的orm框架,例如Hibernate
和Mybatis
等。