Spring中的JdbcTemplate
JdbcTemplate的作用:
如何创建该对象:public static void main ( String[ ] args) {
DriverManagerDataSource ds = new DriverManagerDataSource ( ) ;
ds. setDriverClassName ( "com.mysql.jdbc.Driver" ) ;
ds. setUrl ( "jdbc:mysql://localhost:3306/eesy" ) ;
ds. setUsername ( "root" ) ;
ds. setPassword ( "1234" ) ;
JdbcTemplate jt = new JdbcTemplate ( ) ;
jt. setDataSource ( ds) ;
jt. execute ( "insert into account(name,money)values('ccc',1000)" ) ;
}
对象中的常用方法: public static void main ( String[ ] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext ( "bean.xml" ) ;
JdbcTemplate jt = ac. getBean ( "jdbcTemplate" , JdbcTemplate. class ) ;
jt. update ( "insert into account(name,money)values(?,?)" , "eee" , 3333f ) ;
jt. update ( "update account set name=?,money=? where id=?" , "test" , 4567 , 7 ) ;
jt. update ( "delete from account where id=?" , 8 ) ;
List< Account> accounts = jt. query ( "select * from account where money > ?" , new BeanPropertyRowMapper < Account> ( Account. class ) , 1000f ) ;
for ( Account account : accounts) {
System. out. println ( account) ;
}
List< Account> accounts = jt. query ( "select * from account where id = ?" , new BeanPropertyRowMapper < Account> ( Account. class ) , 1 ) ;
System. out. println ( accounts. isEmpty ( ) ? "没有内容" : accounts. get ( 0 ) ) ;
Long count = jt. queryForObject ( "select count(*) from account where money > ?" , Long. class , 1000f ) ;
System. out. println ( count) ;
数据源:spring的内置数据源
< bean id = " accountDao" class = " com.itheima.dao.impl.AccountDaoImpl" >
< property name = " dataSource" ref = " dataSource" > </ property>
</ bean>
< bean id = " dataSource" class = " org.springframework.jdbc.datasource.DriverManagerDataSource" >
< property name = " driverClassName" value = " com.mysql.jdbc.Driver" > </ property>
< property name = " url" value = " jdbc:mysql://localhost:3306/eesy" > </ property>
< property name = " username" value = " root" > </ property>
< property name = " password" value = " 1234" > </ property>
</ bean>
JdbcDaoSupport类
public class JdbcDaoSupport {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate ( JdbcTemplate jdbcTemplate) {
this . jdbcTemplate = jdbcTemplate;
}
public JdbcTemplate getJdbcTemplate ( ) {
return jdbcTemplate;
}
public void setDataSource ( DataSource dataSource) {
if ( jdbcTemplate == null) {
jdbcTemplate = createJdbcTemplate ( dataSource) ;
}
}
private JdbcTemplate createJdbcTemplate ( DataSource dataSource) {
return new JdbcTemplate ( dataSource) ;
}
}
JdbcTemplate和querryRunner的区别
AOP的事务控制
基于XML
< bean id = " txManager" class = " com.itheima.utils.TransactionManager" >
< property name = " connectionUtils" ref = " connectionUtils" > </ property>
</ bean>
< aop: config>
< aop: pointcut id = " pt1" expression = " execution(* com.itheima.service.impl.*.*(..))" > </ aop: pointcut>
< aop: aspect id = " txAdvice" ref = " txManager" >
< aop: before method = " beginTransaction" pointcut-ref = " pt1" > </ aop: before>
< aop: after-returning method = " commit" pointcut-ref = " pt1" > </ aop: after-returning>
< aop: after-throwing method = " rollback" pointcut-ref = " pt1" > </ aop: after-throwing>
< aop: after method = " release" pointcut-ref = " pt1" > </ aop: after>
</ aop: aspect>
</ aop: config>
基于注解
@Component ( "txManager" )
@Aspect
public class TransactionManager {
@Autowired
private ConnectionUtils connectionUtils;
@Pointcut ( "execution(* com.itheima.service.impl.*.*(..))" )
private void pt1 ( ) { }
public void beginTransaction ( ) {
try {
connectionUtils. getThreadConnection ( ) . setAutoCommit ( false ) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
}
public void commit ( ) {
try {
connectionUtils. getThreadConnection ( ) . commit ( ) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
}
public void rollback ( ) {
try {
connectionUtils. getThreadConnection ( ) . rollback ( ) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
}
public void release ( ) {
try {
connectionUtils. getThreadConnection ( ) . close ( ) ;
connectionUtils. removeConnection ( ) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
}
@Around ( "pt1()" )
public Object aroundAdvice ( ProceedingJoinPoint pjp) {
Object rtValue = null;
try {
Object[ ] args = pjp. getArgs ( ) ;
this . beginTransaction ( ) ;
rtValue = pjp. proceed ( args) ;
this . commit ( ) ;
return rtValue;
} catch ( Throwable e) {
this . rollback ( ) ;
throw new RuntimeException ( e) ;
} finally {
this . release ( ) ;
}
}
}
Spring事务控制
一组API
PlatformTransactionManager接口
此接口是spring的事务管理器,它里面提供了我们常用的操作事务的方法 获取事务状态信息
TransactionStatus getTransaction(TransactionDefinition definition)
提交事务
void commit(TransactionStatus status)
回滚事务
void rollback(TransactionStatus status)
实现类
org.springframework.jdbc.datasource.DataSourceTransactionManager
使用 SpringJDBC 或 iBatis 进行持久化数据时使用org.springframework.orm.hibernate5.HibernateTransactionManager
使用Hibernate 版本进行持久化数据时使用 TransactionDefinition
接口
它是事务的定义信息对象,里面有如下方法 获取事务对象名称
获取事务隔离级别
int getlsolationLevel()
事务的隔离级别4个,spring默认使用的是数据库的隔离级别 获取事务传播行为
int getPropagationBehavior()
什么情况有事务(增删改),什么情况下可有可没有 获取事务超时时间
int getTimeout()
当提交或者回滚,多长时间就过期了 获取事务是否只读
boolean isReadOnly()
只读/读写 TransactionStatus
接口
此接口提供的是事务具体的运行状态,方法介绍如下 刷新事务
获取是否存在存储点
boolean hasSavepoint()
事务是按步提交,设置存储点后,每一步全都完成后提交,如果回滚就是回滚到当前这一步 获取事务是否完成
获取事务是否为新的事务
boolean isNewTransaction()
获取事务是否回滚
设置事务回滚
事务的隔离级别
默认级别
可以读取未提交的数据
ISOLATION_READ_UNCOMMITTED
只能读取已提交数据,解决脏读问题(Oracle默认级别)
是否读取其他事务提交修改后的数据,解决不可重复读问题(mysql默认级别)
ISOLATION_REPEATABLE_READ
是否读取其他事务提交添加后的数据,解决幻读问题
事务的传播行为
REQUIRED
:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值)(增删改)SUPPORTS
:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)MANDATORY
:使用当前的事务,如果当前没有事务,就抛出异常REQUERS_NEW
:新建事务,如果当前在事务中,把当前事务挂起。NOT_SUPPORTED
:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起NEVER
:以非事务方式运行,如果当前存在事务,抛出异常NESTED
:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作。 超过时间
默认值是-1,没有超时限制。如果有,以秒为单位进行设置 是否是只读事务
基于XML
配置事务管理器 配置事务通知
此时我们需要导入事务的约束
使用tx:advide
配置事务的通知
id属性:给事务通知起一个唯一标识 transaction-manager:给事务通知提供一个事务管理器引用 使用aop:config
配置aop中的通用切入点表达式 aop:pointcout
建立事务通知和切入点表达式的对应关系配置事务的属性
是在事务的通知tx:advide
标签的内部 isolation
:用于指定事务的隔离级别,默认值是DEFAULT,表示使用数据库的隔离级别propagation
:用于指定事务的传播行为,默认值REQUIRED,表示一定有事务(增删改),查询方法可以选择SUPPORTSread-only
:用于指定事务是否只读,只有查询方法才能设置为true。默认值falsetimeout
:用于指定事务超时时间,默认值-1,表示永不超时。如果指定了数值,那么以秒为单位rollback-for
:用于指定一个异常,当产生该异常时事务回滚,产生其他异常时事务不回滚,没有默认值,表示任何异常都回滚no-rollback-for
:表示指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚,没有默认值,表示任何异常都回滚
基于xml的实例
<?xml version="1.0" encoding="UTF-8"?>
< beans xmlns = " " xmlns: xsi= " " xmlns: aop= " " xmlns: tx= " " xsi: schemaLocation= " " >
< bean id = " accountService" class = " com.itheima.service.impl.AccountServiceImpl" >
< property name = " accountDao" ref = " accountDao" > </ property>
</ bean>
< bean id = " accountDao" class = " com.itheima.dao.impl.AccountDaoImpl" >
< property name = " dataSource" ref = " dataSource" > </ property>
</ bean>
< bean id = " dataSource" class = " org.springframework.jdbc.datasource.DriverManagerDataSource" >
< property name = " driverClassName" value = " com.mysql.jdbc.Driver" > </ property>
< property name = " url" value = " jdbc:mysql://localhost:3306/eesy" > </ property>
< property name = " username" value = " root" > </ property>
< property name = " password" value = " 1234" > </ property>
</ bean>
< bean id = " transactionManager" class = " org.springframework.jdbc.datasource.DataSourceTransactionManager" >
< property name = " dataSource" ref = " dataSource" > </ property>
</ bean>
< tx: advice id = " txAdvice" transaction-manager = " transactionManager" >
< tx: attributes>
< tx: method name = " *" propagation = " REQUIRED" read-only = " false" />
< tx: method name = " find*" propagation = " SUPPORTS" read-only = " true" > </ tx: method>
</ tx: attributes>
</ tx: advice>
< aop: config>
< aop: pointcut id = " pt1" expression = " execution(* com.itheima.service.impl.*.*(..))" > </ aop: pointcut>
< aop: advisor advice-ref = " txAdvice" pointcut-ref = " pt1" > </ aop: advisor>
</ aop: config>
</ beans>
基于注解的声明式事务配置
名称空间多一个xmlns:context=""
,约束也多一个context
配置事务管理器 使用tx:annotation-driven
开启spring对注解事务的支持 在需要事务支持的地方使用@Transactional
注解
< bean id = " transactionManager" class = " org.springframework.jdbc.datasource.DataSourceTransactionManager" >
< property name = " dataSource" ref = " dataSource" > </ property>
</ bean>
< tx: annotation-driven transaction-manager = " transactionManager" > </ tx: annotation-driven>
纯注解开发实例
@Configuration
@ComponentScan ( "com.itheima" )
@Import ( { JdbcConfig. class , TransactionConfig. class } )
@PropertySource ( "jdbcConfig.properties" )
@EnableTransactionManagement
public class SpringConfiguration {
}
public class TransactionConfig {
@Bean ( name= "transactionManager" )
public PlatformTransactionManager createTransactionManager ( DataSource dataSource) {
return new DataSourceTransactionManager ( dataSource) ;
}
}
public class JdbcConfig {
@Value ( "${jdbc.driver}" )
private String driver;
@Value ( "${jdbc.url}" )
private String url;
@Value ( "${jdbc.username}" )
private String username;
@Value ( "${jdbc.password}" )
private String password;
@Bean ( name= "jdbcTemplate" )
public JdbcTemplate createJdbcTemplate ( DataSource dataSource) {
return new JdbcTemplate ( dataSource) ;
}
@Bean ( name= "dataSource" )
public DataSource createDataSource ( ) {
DriverManagerDataSource ds = new DriverManagerDataSource ( ) ;
ds. setDriverClassName ( driver) ;
ds. setUrl ( url) ;
ds. setUsername ( username) ;
ds. setPassword ( password) ;
return ds;
}
}
@Service ( "accountService" )
@Transactional ( propagation= Propagation. SUPPORTS, readOnly= true )
public class AccountServiceImpl implements IAccountService {
@Autowired
private IAccountDao accountDao;
@Override
public Account findAccountById ( Integer accountId) {
return accountDao. findAccountById ( accountId) ;
}
@Transactional ( propagation= Propagation. REQUIRED, readOnly= false )
@Override
public void transfer ( String sourceName, String targetName, Float money) {
System. out. println ( "transfer...." ) ;
Account source = accountDao. findAccountByName ( sourceName) ;
Account target = accountDao. findAccountByName ( targetName) ;
source. setMoney ( source. getMoney ( ) - money) ;
target. setMoney ( target. getMoney ( ) + money) ;
accountDao. updateAccount ( source) ;
accountDao. updateAccount ( target) ;
}
}
@RunWith ( SpringJUnit4ClassRunner. class )
@ContextConfiguration ( classes= SpringConfiguration. class )
public class AccountServiceTest {
@Autowired
private IAccountService as;
@Test
public void testTransfer ( ) {
as. transfer ( "aaa" , "bbb" , 100f ) ;
}
}
Spring编程式事务
Spring5新特性