spring对数据库的操作:jdbcTemplate操作及事务管理
1.jdbcTemplate操作数据库:
1. 导入jar包(3个)
spring-jdbc-4.2.4.RELEASE.jar
spring-tx-4.2.4.RELEASE.jar
以及jdbc驱动jar包
2. 创建连接池
DriverManagerDataSource dataSource = new DriverManagerDataSource(); //为spring内置连接池
3. 设置连接池参数
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///springtest");
dataSource.setUsername("root");
dataSource.setPassword("abc");
4. 创建JdbcTemplate对象设置参数
JdbcTemplate jdbcTemplate=new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
6. 执行sql语句
jdbcTemplate.execute("update t_user set name=‘张三‘ where id=1");//execute方法可以执行任意sql
总结:jdbcTemplate类似于jdbcUtils中的queryrunner对象,需要传入一个连接池,可以执行sql语句
2.使用spring容器简化上述操作
将连接池对象DriverManagerDataSource,和temple对象jdbcTemplate都交给spring管理
1. applicationContext.xml配置:
spring内置的连接池DriverManagerDataSource,如下: //如果要使用c3p0连接池:先导入两个c3p0的两个jar包,在下面的class中传入ComboPooledDataSource全类名,并采用set方法设置响应属性即可
<bean id="driverManagerDateSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" /> //采用set方法注入属性,DriverManagerDataSource有对应的set方法
<property name="url" value="jdbc:mysql:///springtest" />
<property name="username" value="root" />
<property name="password" value="abc"></property>
</bean>
配置jdbcTemplate
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="driverManagerDateSource"></property> //set方法注入属性
</bean>
2. 简化后操作:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class JdbcTemplateTest2 {
@Autowired
private JdbcTemplate jdbcTemplate; //从spring容器中获取对象
@Test
public void test1() {
jdbcTemplate.execute("update t_user set sex=‘女‘"); //执行sql语句
}
}
3.通过JdbcDaoSurport 获取jdbctemplate进一步简化操作 //只需要向jdbcDaoSurport中注入连接池即可
JdbcDaoSurport类中声明了jdbctemplate和setJdbcTemplate(),和连接池setDataSource()方法。
public class AccountDAOImpl extends JdbcDaoSupport implements IAccountDAO { //让dao继承JdbcDaoSuppory,需要注入连接池
@Override
public void accountOut(String outname, double money) {
this.getJdbcTemplate().update("update account set money=money-? where name=?", money, outname); //注入连接池后,直接调用getJdbcTemplate();的方法获取JdbcTemplate对象
}
}
如果使用注解方式,注入dataSource的方式:
@Component
public class AccountDAOImpl extends JdbcDaoSupport implements IAccountDAO {
@Autowired
public void setDs(DataSource ds){ //注入时,会在spring容器中查找DataSource的实现类对象,并当作参数传入
super.setDataSource(ds); //调用父类的方法实现连接池注入,注入连接池后,父类会自动创建jdbcTemplate对象
}
...
}
4.Jdbctemplate应用--crud操作
增删改:update(""); //传入sql语句,与queryrunner一样
jdbcTemplate.update("update t_user set name=? where id=?", "tom", 1); //sql语句还可以是insert into 或delete from ...
查:queryForObject("",class);
5.引入外部属性文件properties
1. 创建properties属性文件如:db.properties
2. 在applicationContext.xml中引入properties文件:
<context:property-placeholder location="classpath:db.properties" />
3. 在配置文件或注解中均可使用${name}方式来获取属性:
<!-- 创建c3p0连接滨 -->
<bean id="c3p0DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}" /> //获取properties外部文件中的属性并注入
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" /> //jdbc.username如果改为usesrname会出错??
<property name="password" value="${jdbc.password}" />
</bean>
6.事务管理机制(三个接口):
1. PlatformTransactionManager --->平台事务管理器,在不同的持久化层,事务代码不一样
常用的实现类:
DataSourceTransactionManager 主要针对于JdbcTemplate开发 MyBatis开发
HibernateTransactionManasger 主要针对于Hibernate开发
JpaTransactionManager 主要针对于JPA开发
接口中的三个方法:
getTransaction(); //开启事务
commit(); //提交事务
rollback(); //回滚事务
2. TransactionDefinition --->定义事务的一些相关信息 例如 隔离 传播 超时 只读
隔离:
ISOLATION_DEFUALT 它使用后端数据库的默认隔离级别(spring中选项)
ISOLATION_READ_UNCOMMITTED 不能解决问题,会发生脏读 不可重复读 虚读
ISOLATION_READ_COMMITTED 可以解决脏读 会产生不可重复读与虚读。
ISOLATION_REPEATABLE_READ 可以解决脏读,不可重复读 解决不了虚读
ISOLATION_SERIALIZABLE 串行化,可以解决所有问题
传播: //解决的是两个被事务管理的方法互相调用问题(A调用B)。它与数据库没关系,是程序内部维护的问题
PROPAGATION_REQUIRED 默认值 两个操作处于同一个事务,如果之前没有事务,新建一个事务。 两个事务要么同时成功,要么同时失败
PROPAGATION_REQUIRES_NEW B会新建一个事务,两个操作处于不同的事务,A和B互不影响
PROPAGATION_NESTED 它是一种嵌套事务,它是使用SavePoint来实现的。A可以影响B,但是B不能影响A。事务回滚时可以回滚到指定的savepoint, 注意:它只对DataSourceTransactionManager有作用
PROPAGATION_SUPPORTS 支持当前事务,如果不存在,就不使用事务
PROPAGATION_MANDATORY 支持当前事务,如果不存在,抛出异常
PROPAGATION_NOT_SUPPORTED 以非事务运行,如果有事务存在,挂起当前事务
PROPAGATION_NEVER 以非事务运行,如果有事务存在,抛出异常
超时:int TIMEOUT_DEFAULT = -1; 默认值是-1 它使用的是数据库默认的超时时间
只读:boolean isReadOnly(); 它的值有两个true/false,如果选择true一般是在select操作时
3. TransactionStatus --->定义了事务状态信息,在事务运行过程中,得到某个时间点的状态
7.spring事务管理-事务管理两种方式
1. 编码方案 不建议使用,它具有侵入性。在原有的业务代码基础上去添加事务管理代码
@Autowired
private PlatformTransactionManager transactionManager; //注入方式获取事务管理器对象
@Override
public void account(String outname, String inname, double money) {
DefaultTransactionDefinition def = new DefaultTransactionDefinition(); //创建TransactionDefinition实现类对象
def.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ); //设置事务相关信息参数
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
def.setReadOnly(false);
def.setTimeout(TransactionDefinition.TIMEOUT_DEFAULT);
TransactionStatus status = transactionManager.getTransaction(def); //开启事务,需要传入事务定义TransactionDefinition对象
//此处得到的是一个事务状态的对象
try {
// 逻辑代码
// 从outname转出money
accountDao.accountOut(outname, money);
int a = 10 / 0; // 一定会抛出异常
// 向inname转入money
accountDao.accountIn(inname, money);
} catch (Exception e) {
//事务回滚
transactionManager.rollback(status); //传入事务状态对象记录状态信息
} finally {
//提交事务
transactionManager.commit(status);
}
}
总结:三个接口的对象相互配合完成事务控制,PlatformTransactionManager对象负责开启、关闭、回滚事务,
TransactionDefinition,负责封装事务相关信息, TransactionStatus负责记录事务状态信息
2. 声明式事务控制,基于AOP对目标进行代理,添加around环绕通知。 //优点:不具有侵入性,不需要修改原来的业务代码
a.xml 配置文件实现
第一步:在applicationContext.xml文件中添加aop与tx的名称空间
第二步:配置事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="c3p0DataSource"/> //需要注入连接池
</bean>
第三步:配置通知 //Spring为我们提供了一个TransactionInterceptor来完成增强, 对于这个增强,可以使用spring为我们提供的一个标签<tx:advice>来完成操作
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="account" />
</tx:attributes>
</tx:advice>
<tx:method>中的属性 //相当于定义事务相关信息
name:必须的,对哪些方法进行事务控制
isolation 可选 设置事务隔离级别 默认是DEFAULT
propagation:可选 设置事务传播 默认值 REQUIRED
timeout 可选 超时时间 默认值-1
read-only 可选 默认值是false 如果不是只读,它可以对insert update delete操作,如果是只读不可以。
rollback-for 可选 可以设置一个异常,如果产生这个异常,触发事务回滚
no-rolback-for 可选 可以设置一个异常,如果产生这个异常,不会触发事务回滚
第四步:配置切面 //使用的是传统的spring的advice,需要使用<aop:advisor>标签配置切面
<aop:config>
<aop:pointcut
expression="execution(* cn.itheima.service.IAccountService.account(..))" id="txPointcut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
b.注解实现
1. 配置事务管理器 //需要提前配置连接池
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="c3p0DataSource"/> //必须注入dataSource
</bean>
2. 开启注解事务
<tx:annotation-driven transaction-manager="transactionManager"/> //必须传入事务管理器
3. 方法或类上使用注解:
@Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED,readOnly=false) //可以在括号中加入事务信息,也可省略
@Override
public void account(String outname, String inname, double money) {
// 从outname转出money
accountDao.accountOut(outname, money);
int a = 10 / 0; // 一定会抛出异常
// 向inname转入money
accountDao.accountIn(inname, money);
}
this的用法:为当前类的对象的引用,当子类对象调用父类成员时,父类中的this相当于下面的f:
Z继承F
F f=new Z(); 这里的f就类似于this
此时this为子类对象的父类引用(多态),当调用getClass()方法时,获取的时子类的字节码对象
原文地址:https://www.cnblogs.com/liuxuelin/p/9973750.html