一、 spring的JDBC
spring的DAO模块提供了对JDBC的支持。JdbcTemplage是springJDBC支持中主要的API,提供了访问数据库的一般功能。
实现步骤:
1. 搭建数据库
2. 引入需要的jar包
3. 编写代码业务
4. 例子
1) 在类中直接使用spring自带的连接池
创建执行连接数据库的类
public interfaceAccountDao {
public voidgetDataSource();
}
@Controller
public classAccountDaoImpl implements AccountDao{
public voidgetDataSource(){
DriverManagerDataSource dataSource=newDriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/jdbc_transaction?useUnicode=true&characterEncoding=utf8");
dataSource.setUsername("root");
dataSource.setPassword("1234");
JdbcTemplate jdbcTemplate=newJdbcTemplate(dataSource);
String sql="insertinto account values (null,?,?)";
jdbcTemplate.update(sql,"aa",10000);
}
}
配置xml
<!-- 开启注解扫描 -->
<context:component-scanbase-package="com.spring.tx"></context:component-scan>
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext3.xml")
public classTestJdbcTemplate {
@Autowired
private AccountDao accoutDaoImpl;
@Test
public voidtestJTemplate(){
accoutDaoImpl.getDataSource();
}
}
2) 将数据连接池交给spring管理,即采用xml配置连接池
分析xml配置,首先,在使用jdbc连接数据库的类中,使用了dataSource,首先将连接池交给spring的xml,其次,JdbcTemplate使用了dataSource,而且在JdbcTemplate类中,dataSource是这个类的一个属性,所以,可以把dataSource注入这个类。
创建执行数据库连接的类
@Controller
public classAccountDaoImpl implements AccountDao{
@Autowired
private JdbcTemplate jdbcTemplate;
public void getDataSourceXml(){
String sql="insertinto account values (null,?,?)";
jdbcTemplate.update(sql,"xmljdbc",10000);
}
}
配置xml
<!-- 开启注解扫描 -->
<context:component-scanbase-package="com.spring.tx"></context:component-scan>
<!-- 配置datasource的bean组件 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<propertyname="driverClassName"value="com.mysql.jdbc.Driver"/>
<propertyname="url"value="jdbc:mysql://localhost:3306/jdbc_transaction?useUnicode=true&characterEncoding=utf8"/>
<propertyname="username"value="root"/>
<propertyname="password"value="1234"/>
</bean>
<!-- 将dataSource注入JdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<propertyname="dataSource"ref="dataSource"/>
</bean>
测试略
3) 关于将dbcp和c3p0的连接池交给spring管理的xml配置
在导入相关jar包的前提下
Dbcp
<!-- 配置dbcp -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<propertyname="driverClassName"value="com.mysql.jdbc.Driver"/>
<propertyname="url"value="jdbc:mysql://localhost:3306/jdbc_transaction?useUnicode=true&characterEncoding=utf8"/>
<propertyname="username"value="root"/>
<propertyname="password"value="1234"/>
</bean>
C3p0
<!-- 配置c3p0 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<propertyname="driverClass"value="com.mysql.jdbc.Driver"/>
<propertyname="jdbcUrl"value="jdbc:mysql://localhost:3306/jdbc_transaction?useUnicode=true&characterEncoding=utf8"/>
<propertyname="user"value="root"/>
<propertyname="password"value="1234"/>
</bean>
4) 关于使用JdbcTemplate执行增删改查操作
A. 增删改
public voidgetDataSourceXml(){
String sql="insertinto account values (null,?,?)";
jdbcTemplate.update(sql,"xmljdbc",10000);
}
public void update(){
String sql="updateaccount set name=? where id=?";
jdbcTemplate.update(sql,"haha",905);
}
public void delete(){
String sql="deletefrom account where id=?";
jdbcTemplate.update(sql, 906);
}
测试略
B. 查
在查询的实现中,需要配置对象关系映射类,这种操作思路是一般持久层框架会涉及到的。
public Account selectOne(){
String sql="select* from account where id=?";
return jdbcTemplate.queryForObject(sql, newBeanMapper(), 905);
}
public List<Account>select(){
String sql="select* from account";
List<Account> alist=jdbcTemplate.query(sql,newBeanMapper());
return alist;
}
创建对象关系映射类
//创建字段映射类,对象关系映射,一些持久层框架也涉及到对象的关系映射
public classBeanMapper implements RowMapper<Account>{
public AccountmapRow(ResultSetrs, intarg1) throwsSQLException {
Account ac=newAccount();
ac.setId(rs.getInt("id"));
ac.setName(rs.getString("name"));
ac.setMoney(rs.getDouble("money"));
return ac;
}
}
二、 spring的事务实现
关于事务的介绍,请见。http://blog.csdn.net/xingzhishen/article/details/76559566
(一) 相关的类和接口
1. PlatformTransactionManager
平台事务管理器,管理事物的类。通过不同的实现类,在不同的持久层框架,实现事务。
常用的实现类是:DataSourceTransactionManager
PlatformTransactionManager的方法
| commit |
getTransaction | |
| rollback |
2. TransactionDefinition
事务定义接口,专门用于设定事务的属性。(如事务的隔离等级,传播行为,超时,只读等)
属性列表
| ISOLATION_DEFAULT |
| ISOLATION_READ_COMMITTED |
| ISOLATION_READ_UNCOMMITTED |
| ISOLATION_REPEATABLE_READ |
| ISOLATION_SERIALIZABLE |
| PROPAGATION_MANDATORY |
| PROPAGATION_NESTED |
| PROPAGATION_NEVER |
| PROPAGATION_NOT_SUPPORTED |
| PROPAGATION_REQUIRED |
| PROPAGATION_REQUIRES_NEW |
| PROPAGATION_SUPPORTS |
| TIMEOUT_DEFAULT |
上面的属性,分别涉及到隔离等级,传播行为和超时。
事务的隔离等级:
PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED--嵌套事务,当A执行之后,就会在这个位置设置一个保存点。如果B没有问题,执行通过。如果B出现异常,运行客户根据需求回滚(选择回滚到保存点或者是最初始状态)。
3. TransactionStatus
事务状态接口,这个接口中的setRollbackOnly()方法,可以实现事务的阻塞提交,对事务进行回滚。
(二) 实现事务的两种方式
业务需求,a账户向b账户转账。
业务分析,保证a出钱和b得钱的事务实现。
1. 编写基本业务
A. 创建web工程,导入jar包
B. 创建处理事务的类和三层结构包
C. 配置xml
D. 在dao层注入jdbc模板
E. 编写业务代码
F. 测试
G. 例子
创建三层的业务流程
Dao层
public interfaceAccountDao {
public voidoutMoney(String name,doublemoney);
public voidinMoney(String name,doublemoney);
}
@Repository
public classAccountDaoImpl extends JdbcDaoSupportimplementsAccountDao{
public voidoutMoney(String name, double money) {
String sql="updateaccount set money=money-? where name=?";
this.getJdbcTemplate().update(sql,money,name);
}
public voidinMoney(String name, double money) {
String sql="updateaccount set money=money+? where name=?";
this.getJdbcTemplate().update(sql,money,name);
}
}
Service层
public interfaceAccountService {
public voidtransfer(String name1,Stringname2,doublemoney);
}
@Service
public classAccountServiceImpl implements AccountService{
@Autowired
private AccountDao accountDaoImpl;
@Override
public voidtransfer(String name1, Stringname2, doublemoney) {
accountDaoImpl.outMoney(name1,money);
accountDaoImpl.inMoney(name2,money);
}
}
Web层或者测试层
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext4.xml")
public classTestTransaction {
@Autowired
private AccountService accountServiceImpl;
@Test
public voidtestTransaction(){
accountServiceImpl.transfer("aa","bb",1000);
}
}
配置xml
<!-- 开启注解扫描 -->
<context:component-scanbase-package="com.spring.tx2"></context:component-scan>
<!-- 配置c3p0 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<propertyname="driverClass"value="com.mysql.jdbc.Driver"/>
<propertyname="jdbcUrl"value="jdbc:mysql://localhost:3306/jdbc_transaction?useUnicode=true&characterEncoding=utf8"/>
<propertyname="user"value="root"/>
<propertyname="password"value="1234"/>
</bean>
<!-- 将dataSource注入JdbcTemplate-->
<!-- <beanid="jdbcTemplate"class="org.springframework.jdbc.core.JdbcTemplate" >
<propertyname="dataSource" ref="dataSource" />
</bean> -->
<bean id="accountDaoImpl" class="com.spring.tx2.AccountDaoImpl">
<propertyname="dataSource"ref="dataSource"/>
</bean>
H. 关于简化dao层,spring提供了很多用于简化dao层开发的类。在jdbc连接数据库上,dao层类可以继承JdbcDaoSupport类。由于这个类拥有下面的属性和方法:
privateJdbcTemplate jdbcTemplate;
public final voidsetDataSource(DataSourcedataSource) {
if (this.jdbcTemplate ==null || dataSource != this.jdbcTemplate.getDataSource()){
this.jdbcTemplate =createJdbcTemplate(dataSource);
initTemplateConfig();
}
}
Jdbcdao支持类中,带有jdbc模板,而且已经set dataSource,所以在xml或者注解中不用再赋予dao层类jdbc模板对象,只需赋予其dataSource属性就可以从父类生成jdbc模板。
2. 编程式事务管理
通过编写java代码的方式,实现事务。Spring提供了管理事务的模板TransactionTemplate,简化了编程式事务的代码,但是一般不常用这种方式。
步骤:
A. 配置事务管理器,实现PlatformTransactionManager。
B. 配置事务管理模板。
C. 将事务管理模板注入事务管理类
D. 在事务业务层使用事务管理模板实现事务
E. 例子
配置事务管理器
<!-- 开启注解扫描 -->
<context:component-scanbase-package="com.spring.tx2"></context:component-scan>
<!-- 配置c3p0 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<propertyname="driverClass"value="com.mysql.jdbc.Driver"/>
<propertyname="jdbcUrl"value="jdbc:mysql://localhost:3306/jdbc_transaction?useUnicode=true&characterEncoding=utf8"/>
<propertyname="user"value="root"/>
<propertyname="password"value="1234"/>
</bean>
<!-- 将dataSource注入JdbcTemplate-->
<!-- <bean id="jdbcTemplate"class="org.springframework.jdbc.core.JdbcTemplate" >
<propertyname="dataSource" ref="dataSource" />
</bean> -->
<bean id="accountDaoImpl" class="com.spring.tx2.AccountDaoImpl">
<propertyname="dataSource"ref="dataSource"/>
</bean>
<!-- 配置事务管理器
事务的执行,需要保证连接的唯一,所以要把dataSource注入事务管理类
-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<propertyname="dataSource"ref="dataSource"/>
</bean>
<!-- 配置事务管理模板 -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<propertyname="transactionManager"ref="transactionManager"/>
</bean>
<!-- 将事务模板注入需要实现事务的业务类 -->
<bean id="accountServiceImpl" class="com.spring.tx2.AccountServiceImpl">
<propertyname="transactionTemplate"ref="transactionTemplate"/>
</bean>
在业务层使用事务模板实现事务
public classAccountServiceImpl implements AccountService{
private TransactionTemplatetransactionTemplate;
public voidsetTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate =transactionTemplate;
}
@Autowired
private AccountDao accountDaoImpl;
@Override
public void transfer(final Stringname1,final Stringname2,finaldouble money) {
transactionTemplate.execute(newTransactionCallbackWithoutResult() {
protected voiddoInTransactionWithoutResult(TransactionStatus arg0) {
accountDaoImpl.outMoney(name1,money);
accountDaoImpl.inMoney(name2,money);
}
});
}
}
3. 声明式事务管理
声明式事务管理底层采用了AOP技术实现。
1) 基于AspectJ的xml的方式
核心步骤:
A. 配置事务管理器
B. 配置事务增强,即事务通知,就是要使用事务管理器来作用于事务单元
C. 配置配置AOP的切面,即形成事务增强与切入点的实现,通过切面将事务增强到事务单元
D. 测试
E. 例子
配置事务管理器,事务增强,以及切面,所有的业务都在xml中实现
<!-- 开启注解扫描 -->
<context:component-scanbase-package="com.spring.tx2"></context:component-scan>
<!-- 配置c3p0 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<propertyname="driverClass"value="com.mysql.jdbc.Driver"/>
<propertyname="jdbcUrl"value="jdbc:mysql://localhost:3306/jdbc_transaction?useUnicode=true&characterEncoding=utf8"/>
<propertyname="user"value="root"/>
<propertyname="password"value="1234"/>
</bean>
<!-- 将dataSource注入JdbcTemplate-->
<!-- <bean id="jdbcTemplate"class="org.springframework.jdbc.core.JdbcTemplate" >
<propertyname="dataSource" ref="dataSource" />
</bean> -->
<bean id="accountDaoImpl" class="com.spring.txxml.AccountDaoImpl">
<propertyname="dataSource"ref="dataSource"/>
</bean>
<!-- 配置事务管理器
使用PlatformTransactionManager的实现类DataSourceTransactionManager
事务的执行,需要保证连接的唯一,所以要把dataSource注入事务管理类
-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<propertyname="dataSource"ref="dataSource"/>
</bean>
<!-- 配置事务增强的方法及其属性 -->
<tx:adviceid="txAdvice"transaction-manager="transactionManager">
<!-- 配置添加事务的方法
同时,可以为事务的业务设置不同的属性
-->
<tx:attributes>
<tx:methodname="transfer"/>
</tx:attributes>
</tx:advice>
<!-- 配置切面 -->
<aop:config>
<aop:advisoradvice-ref="txAdvice"pointcut="execution(**..*.AccountServiceImpl.transfer(..))"/>
</aop:config>
<bean id="accountServiceImpl" class="com.spring.txxml.AccountServiceImpl"/>
F. 设置事务的相关属性
isolation:设置隔离等级 propagation:设置传播行为 time-out:设置超时时限 read-only:设置只读
实例略,请按需配置。形式如:
<tx:method name="transfer"isolation="DEFAULT"propagation="REQUIRED"read-only="false"timeout="-1"/>
2) 基于AspectJ的注解方式
核心步骤:
A. 配置事务管理器
B. 开启事务管理的注解功能
C. 在事务实现类上标注@Transactional
D. 测试
E. 例子
配置事务管理器和开启事务注解
<!-- 配置事务管理器
使用PlatformTransactionManager的实现类DataSourceTransactionManager
事务的执行,需要保证连接的唯一,所以要把dataSource注入事务管理类
-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<propertyname="dataSource"ref="dataSource"/>
</bean>
<!-- 开启事务的注解功能 -->
<tx:annotation-driventransaction-manager="transactionManager"/>
标注事务类或事务方法
//标注类的注解,为所有的方法添加事务处理,也可以单独用在某个方法上。
@Transactional
public classAccountServiceImpl implements AccountService{
@Autowired
private AccountDao accountDaoImpl;
@Override
public voidtransfer(String name1,Stringname2,doublemoney) {
accountDaoImpl.outMoney(name1,money);
accountDaoImpl.inMoney(name2,money);
}
}