学习目标:
Spring的数据库编程:数据库编程是互联网编程的基础,Spring框架为开发者提供了JDBC模板模式,即jdbcTemplate,它可以简化许多代码,但在实际应用中jdbcTemplate并不常用。工作更多的时候,用的是Hibernate框架和MyBatis框架进行数据库编程。
学习大纲:
一、Spring JDBC的XML配置
二、Spring JDBC的Java配置
三、Spring JdbcTemplate的常用方法
四、基于@Transactional注解的声明式事务管理
学习内容:
一、Spring JDBC的XML配置
本节Spring数据库编程主要使用Spring JDBC模块的core和dataSource包。core包是JDBC的核心功能包,包括常用的JdbcTemplate类;dataSource包是访问数据源的工具类包。使用Spring JDBC操作数据库,需要对其进行配置。
<!-- 配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- MySQL数据库驱动 -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<!-- 连接数据库的URL -->
<property name="url" value="jdbc:mysql://localhost:3306/springtest?characterEncoding=utf8"/>
<!-- 连接数据库的用户名 -->
<property name="username" value="root"/>
<!-- 连接数据库的密码 -->
<property name="password" value="root"/>
</bean>
<!-- 配置JDBC模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
配置JDBC模板时,需要将dataSource注入到jdbcTemplate,而在数据访问层(如Dao类)使用jdbcTemplate时,也需要将jdbcTemplate注入到对应的Bean中。代码示例如下:
……
@Repository
public class TestDaoImpl implements TestDao{
@Autowired
//使用配置文件中的JDBC模板
private JdbcTemplate jdbcTemplate;
……
}
二、Spring JDBC的Java配置
@Configuration //通过该注解来表明该类是一个Spring的配置,相当于一个xml文件
@ComponentScan(basePackages = "dao") //配置扫描包
@PropertySource(value={"classpath:jdbc.properties"},ignoreResourceNotFound=true)
//配置多个属性文件时 value={"classpath:jdbc.properties","xx","xxx"}
public class SpringJDBCConfig {
@Value("${jdbc.url}")//注入属性文件jdbc.properties中的jdbc.url
private String jdbcUrl;
@Value("${jdbc.driverClassName}")
private String jdbcDriverClassName;
@Value("${jdbc.username}")
private String jdbcUsername;
@Value("${jdbc.password}")
private String jdbcPassword;
/**
* 配置数据源
*/
@Bean
public DriverManagerDataSource dataSource() {
DriverManagerDataSource myDataSource = new DriverManagerDataSource();
// 数据库驱动
myDataSource.setDriverClassName(jdbcDriverClassName);;
// 相应驱动的jdbcUrl
myDataSource.setUrl(jdbcUrl);
// 数据库的用户名
myDataSource.setUsername(jdbcUsername);
// 数据库的密码
myDataSource.setPassword(jdbcUsername);
return myDataSource;
}
/**
* 配置JdbcTemplate
*/
@Bean(value="jdbcTemplate")
public JdbcTemplate getJdbcTemplate() {
return new JdbcTemplate(dataSource());
}
}
三、Spring JdbcTemplate的常用方法
获取JDBC模板后,如何使用它是本节将要讲述的内容。首先,需要了解JdbcTemplate类的常用方法。该类的常用方法是update()和query()方法。
public int update(String sql,Object args[])
该方法可以对数据表进行增加、修改、删除等操作。使用args[]设置SQL语句中的参数,并返回更新的行数。示例代码如下:
String insertSql = "insert into user values(null,?,?)";
Object param1[] = {"chenheng1", "男"};
jdbcTemplate.update(sql, param1);
public List<T> query (String sql, RowMapper<T> rowMapper, Object args[])
该方法可以对数据表进行查询操作。rowMapper将结果集映射到用户自定义的类中(前提是自定义类中的属性要与数据表的字段对应)。示例代码如下:
String selectSql ="select * from user";
RowMapper<MyUser> rowMapper = new BeanPropertyRowMapper<MyUser>(MyUser.class);
List<MyUser> list = jdbcTemplate.query(sql, rowMapper, null);
下面通过一个实例【例1-8】演示Spring JDBC的使用过程
1.使用Eclipse创建Web应用并导入JAR包
2.创建属性文件与配置类
在ch1_8应用的src目录下,创建数据库配置的属性文件jdbc.properties
在ch1_8应用的src目录下,创建config包,并在该包中创建配置类SpringJDBCConfig。在该配置类中使用@PropertySource注解读取属性文件jdbc.properties,并配置数据源和JdbcTemplate
//jdbc.properties属性文件
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/springtest?useSSL=false&serverTimezone=UTC&characterEncoding=utf8
jdbc.username=root
jdbc.password=123456
//SpringJDBCConfig
package config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration //通过该注解来表明该类是一个Spring的配置,相当于一个xml文件
@ComponentScan(basePackages = {"dao","service"}) //配置扫描包
@PropertySource(value={"classpath:jdbc.properties"},ignoreResourceNotFound=true)
@EnableTransactionManagement//开启声明式事务的支持
//配置多个配置文件 value={"classpath:jdbc.properties","xx","xxx"}
public class SpringJDBCConfig {
@Value("${jdbc.url}")//注入属性文件jdbc.properties中的jdbc.url
private String jdbcUrl;
@Value("${jdbc.driverClassName}")
private String jdbcDriverClassName;
@Value("${jdbc.username}")
private String jdbcUsername;
@Value("${jdbc.password}")
private String jdbcPassword;
/**
* 配置数据源
*/
@Bean
public DriverManagerDataSource dataSource() {
DriverManagerDataSource myDataSource = new DriverManagerDataSource();
// 数据库驱动
myDataSource.setDriverClassName(jdbcDriverClassName);
// 相应驱动的jdbcUrl
myDataSource.setUrl(jdbcUrl);
// 数据库的用户名
myDataSource.setUsername(jdbcUsername);
// 数据库的密码
myDataSource.setPassword(jdbcUsername);
return myDataSource;
}
/**
* 配置JdbcTemplate
*/
@Bean(value="jdbcTemplate")
public JdbcTemplate getJdbcTemplate() {
return new JdbcTemplate(dataSource());
}
/**
* 为数据源添加事务管理器
*/
@Bean
public DataSourceTransactionManager transactionManager() {
DataSourceTransactionManager dt = new DataSourceTransactionManager();
dt.setDataSource(dataSource());
return dt;
}
}
3.创建数据表与实体类
使用Navicat for MySQL创建数据库springtest
,并在该数据库中创建数据表user,数据表user的结构如图所示:
在ch1_8应用的src目录下,创建包entity
,在该包中创建实体类MyUser
//MyUser
package entity;
public class MyUser
{
private Integer uid;
private String uname;
private String usex;
//省略set和get方法
public String toString() {
return "myUser[uid="+uid+",uname="+uname+",usex="+usex+"]";
}
}
4.创建数据访问层
在ch1_8应用的src目录下,创建包dao
,在该包中创建数据访问接口TestDao
和接口实现类TestDaoImpl
。在实现类TestDaoImpl
中使用@Repository注解标注此类为数据访问层,并使用@Autowired注解依赖注入JdbcTemplate。
//TestDao
package dao;
import java.util.List;
import entity.MyUser;
public interface TestDao {
public int update(String sql, Object[] param);
public List<MyUser> query(String sql, Object[] param);
}
//TestDaoImpl
package dao;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import entity.MyUser;
@Repository
public class TestDaoImpl implements TestDao{
@Autowired
//使用配置类中的JDBC模板
private JdbcTemplate jdbcTemplate;
/**
* 更新方法,包括添加、修改、删除
* param为sql中的参数,如通配符?
*/
@Override
public int update(String sql, Object[] param) {
return jdbcTemplate.update(sql, param);
}
/**
* 查询方法
* param为sql中的参数,如通配符?
*/
@Override
public List<MyUser> query(String sql, Object[] param) {
RowMapper<MyUser> rowMapper = new BeanPropertyRowMapper<MyUser>(MyUser.class);
return jdbcTemplate.query(sql, rowMapper);
}
}
5.创建业务逻辑层
在ch1_8应用的src
目录下,创建包service
,在该包中创建数据访问接口TestService
和接口实现类TestServiceImpl
。在实现类TestServiceImpl
中使用@Service注解标注此类为业务逻辑层,并使用@Autowired注解依赖注入TestDao。
//TestService
package service;
public interface TestService {
public void testJDBC();
}
//TestServiceImpl
package service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import dao.TestDao;
import entity.MyUser;
@Service
@Transactional
public class TestServiceImpl implements TestService{
@Autowired
public TestDao testDao;
@Override
public void testJDBC() {
String insertSql = "insert into user values(null,?,?)";
//数组param的值与insertSql语句中?一一对应
Object param1[] = {"chenheng1", "男"};
Object param2[] = {"chenheng2", "女"};
Object param3[] = {"chenheng3", "男"};
Object param4[] = {"chenheng4", "女"};
String insertSql1 = "insert into user values(?,?,?)";
Object param5[] = {1,"chenheng5", "女"};
Object param6[] = {1,"chenheng6", "女"};
//添加用户
testDao.update(insertSql, param1);
testDao.update(insertSql, param2);
testDao.update(insertSql, param3);
testDao.update(insertSql, param4);
//添加两个ID相同的用户,出现唯一性约束异常,使事物回滚。
testDao.update(insertSql1, param5);
testDao.update(insertSql1, param6);
//查询用户
String selectSql ="select * from user";
List<MyUser> list = testDao.query(selectSql, null);
for(MyUser mu : list) {
System.out.println(mu);
}
}
}
6.创建测试类
package config;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import service.TestService;
public class TestJDBC {
public static void main(String[] args) {
//初始化Spring容器ApplicationContext
AnnotationConfigApplicationContext appCon =
new AnnotationConfigApplicationContext(SpringJDBCConfig.class);
TestService ts = appCon.getBean(TestService.class);
ts.testJDBC();
appCon.close();
}
}
7.运行测试类
------》解决方案
Exception in thread "main" org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connect ion for transaction; nested exception is java.sql.SQLException: Access denied for user 'root'@'localhost' (using passwor d: YES)
未解决哭哭!
四、基于@Transactional注解的声明式事务管理
@Transactional注解可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有public方法将都具有该类型的事务属性,同时,也可以在方法级别使用该注解来覆盖类级别的定义。虽然@Transactional注解可以作用于接口、接口方法、类以及类方法上,但是Spring小组建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。