一、JdbcTemplate:
1、使用之前,需要导入的jar包:
spring-jdbc-5.0.2.RELEASE.jar
spring-tx-5.0.2.RELEASE.jar
2、spring的事务控制的API:
<1>、PlatformTransactionManager:
(1)、作用:
该接口是提供事务操作的方法。
(2)、具体操作方法:
①、获取事务状态信息:
TransactionStatus getTransaction(TransactionDefinition definition)
②、提交事务:
void commit(TransactionStatus status)
③、回滚事务:
void rollback(TransactionStatus status)
(2)、具体管理事务(实现类)的对象:
①、使用Spring JDBC或iBatis进行持久化数据时使用:
org.springframework.jdbc.datasource.DataSourceTransactionManager、
②、使用Hibernate版本进行持久化数据时使用:
org.springframework.orm.hibernationManager
<2>、TransactionDefinition:
(1)、作用:
该接口是提供事务定义的对象。
(2)、具体操作方法:
①、获取事务对象名称:
String getName()
②、获取事务隔离级别:
Ⅰ、方法名:
int getIsolationLevel()
Ⅱ、方法参数:
ISOLATION_DEFAULT:默认级别,归属下面某一种。
ISOLATION_READ_UNCOMMITTED:可以读未提交数据
ISOLATION_READ_COMMITTED只能读取已提交数据,解决脏读问题(Oracle默认级别)
ISOLATION_REPETABLE_READ:是否读取其他事务提交修改后的数据,解决不可重复读问题(MYSQL默认级别)
ISOLATION_SERIALIZABLE:是否读取其他事务提交添加后的数据,解决幻读问题
③、获取事务传播行为:
Ⅰ、方法名:
int getPropagationBehavior()
Ⅱ、方法参数:
REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,就加入到该事务中。一般的选择,默认值。
SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)
MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常。
REQUERS_NEW:新建事务,如果当前在事务中,就把当前事务挂起。
NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
NEVER:以非事务方式运行,如果当前存在事务,就抛出异常。
NESTED:如果当前存在事务,则在嵌套事务内执行;如果没有事务,则执行REQUIRED类似的操作。
④、获取事务超时时间:
Ⅰ、方法名:
int getTimeout()
Ⅱ、方法参数:
默认值是-1,没有超时限制。如果有,以秒为单位进行设置。
⑤、获取事务是否只读:
Ⅰ、方法名:
boolean isReadOnly()
Ⅱ、方法参数:
建议查询时设置为只读。
<3>、TransactionStatus:
(1)、作用:
描述了某个时间点上事务对象的状态信息。
(2)、具体操作方法:
①、刷新事务:
void flush()
②、获取是否存在存储点:
boolean hasSavepoint()
③、获取事务是否完成:
boolean isCompleted()
④、获取事务是否为新事务:
boolean isNewTransaction()
⑤、获取事务是否回滚:
boolean isRollbackOnly()
⑥、设置事务回滚:
void setRollbackOnly()
二、配置:
1、在XML中配置JdbcTemplate的方法:
2、JdbcTemplate的操作:
<1>、获取容器:
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
<2>、获取对象:
JdbcTemplate jt = ac.getBean("jdbcTemplate",JdbcTemplate.class);
<3>、保存操作:
jt.update("insert into account(name,money)values(?,?)","ttt",3333f);
<4>、更新操作:
jt.update("update account set name = ?,money = ? where id = ?;","aaa",1234,1);
<5>、删除操作:
jt.update("delete from account where id = ?",11);
<6>、查询所有:
List accounts1 =
jt.query("select * from account where money > ?", new AccountRowMapper(),4000f);
List accounts2 =
jt.query("select * from account where money > ?", new BeanPropertyRowMapper(Account.class),4000f);
for(Account account : accounts1){
System.out.println(account);
}
<7>、查询一个:
List accounts =
jt.query("select * from account where money > ?", new BeanPropertyRowMapper(Account.class),4000f);
System.out.println(accounts.isEmpty()? "没有内容" : accounts.get(0));
<8>、查询返回一行一列(使用聚会函数,但不加group by子句):
Long count = jt.queryForObject("Select count(*) from account where money > ?",Long.class,1000f);
System.out.println(count);
2、pring中基于xml的声明式事务配置步骤:
<1>.配置事务管理器:
<2>.配置事务通知:
(1)、注意:
此时需要导入事务的约束;包括tx的名称空间和约束,aop的名称空间和约束。
(2)、使用tx:advice标签配置事务通知时:
id:给事务通知起一个唯一id
transaction-manager:给事务通知提供一个事务管理引用
(3)、配置代码:
<3>、配置AOP中的通用切入点表达式:
<4>、配置事务属性:
(1)、注意:
在事务的通知tx:Advice标签内部配。
(2)、tx:method标签属性:
①、isolation="" :
用于指定事务的隔离级别,默认值是default,表示使用数据库的隔离属性
②、propagation="" :
用于指定事务的传播行为。默认值REQUIRED,表示一定会有事务。增删改的选择。查询方法可以选SUPPORTS。
③、read-only="" :
用于指定事务是否只读。只有查询方法才能设置为True,默认值是false,表示读写。
④、timeout="":
用于指定事务的超时时间。默认值是-1,表示永不超时。如果指定了数值,以秒为单位。
⑤、rollback-for="" :
用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务都不回滚。没有默认值,表示任何异常都回滚。
⑥、no-rollback-for="" :
用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时,事务回滚。没有默认值,表示任何异常都回滚。
<5>.配置数据源:
//1.准备数据源,spring的内置数据源
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/eesy");
ds.setUsername("root");
ds.setPassword("123456");
//2.创建对象
JdbcTemplate jt = new JdbcTemplate();
//3.给对象设置数据源
jt.setDataSource(ds);
//3.执行操作
jt.execute("insert into account(name,money)values('SSS',2222)");
3、pring中基于注解的声明式事务配置步骤:
<1>.配置要扫描的包:
<2>.配置JdbcTemplate:
<3>.配置数据源:
<4>.配置事务管理器:
<5>.开启spring对注解事务的支持:
<6>.在需要事务支持的地方使用@Transaal注解:
//只读型事务配置,配置在类上
@Transactional(propagation = Propagation.SUPPORTS,readOnly = true)
//读写型事务配置,配置在方法上
@Transactional(propagation = Propagation.REQUIRED,readOnly = false)
三、配置完全代码:
1、基于XML的配置:
<1>、在JdbcTemplate类中:
public class JdbcTemplateDemo1 {
public static void main(String[] args) {
//1.准备数据源,spring的内置数据源
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/eesy");
ds.setUsername("root");
ds.setPassword("123456");
//2.创建对象
JdbcTemplate jt = new JdbcTemplate();
//3.给对象设置数据源
jt.setDataSource(ds);
//3.执行操作
jt.execute(SQL操作语句");
}
}
<2>、在bean.xml中:
bean.xml中:
<3>、Service层:
public class AccountService implements IAccountService {
private IAccountDao accountDao;
public void setAccountDao(IAccountDao accountDao) {
this.accountDao = accountDao;
}
public Account findAccountById(Integer accountId) {
return accountDao.findAccountById(accountId);
}
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);
}
}
<4>、Dao层:
public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao {
public Account findAccountById(Integer accountId) {
List accounts = super.
getJdbcTemplate().query("select * from account where money > ?", new BeanPropertyRowMapper(Account.class), accountId);
return accounts.isEmpty() ? null : accounts.get(0);
}
public Account findAccountByName(String accountName) {
List accounts = super.
getJdbcTemplate().query("select * from account where name = ?", new BeanPropertyRowMapper(Account.class),accountName);
if(accounts.isEmpty()){
return null;
}
if(accounts.size() > 1){
throw new RuntimeException("结果集不唯一!!!");
}
return accounts.get(0);
}
public void updateAccount(Account account) {
super.getJdbcTemplate().update("update account set name = ?,money = ? where id = ?",account.getName(),account.getMoney(),account.getId());
}
}
<5>、定义account的封装策略:
class AccountRowMapper implements RowMapper{
/**
* 把结果集中的数据封装到account中,然后由spring把每个Account加到集合中
* @param rs
* @param i
* @return
* @throws SQLException
*/
public Account mapRow(ResultSet rs, int i) throws SQLException {
Account account = new Account();
account.setId(rs.getInt("id"));
account.setName(rs.getString("name"));
account.setMoney(rs.getFloat("money"));
return account;
}
2、基于注解的配置:
<1>、在bean.xml中:
<2>、Service层:
@Service("accountService")
//只读型事务配置
@Transactional(propagation = Propagation.SUPPORTS,readOnly = true)
public class AccountServiceImpl implements IAccountService {
@Autowired
private IAccountDao accountDao;
public Account findAccountById(Integer accountId) {
return accountDao.findAccountById(accountId);
}
//读写型事务配置
@Transactional(propagation = Propagation.REQUIRED,readOnly = false)
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);
int i = 1/0;
//更新转入账户
accountDao.updateAccount(target);
}
}
<3>、Dao层:
@Repository("accountDao")
public class AccountDaoImpl implements IAccountDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public Account findAccountById(Integer accountId) {
List accounts = jdbcTemplate.query("select * from account where money > ?", new BeanPropertyRowMapper(Account.class), accountId);
return accounts.isEmpty() ? null : accounts.get(0);
}
public Account findAccountByName(String accountName) {
List accounts = jdbcTemplate.query("select * from account where name = ?", new BeanPropertyRowMapper(Account.class),accountName);
if(accounts.isEmpty()){
return null;
}
if(accounts.size() > 1){
throw new RuntimeException("结果集不唯一!!!");
}
return accounts.get(0);
}
public void updateAccount(Account account) {
jdbcTemplate.update("update account set name = ?,money = ? where id = ?",account.getName(),account.getMoney(),account.getId());
}
}
<4>、JdbcTemplate:
public class JdbcTemplateDemo1 {
public static void main(String[] args) {
//1.准备数据源,spring的内置数据源
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/eesy");
ds.setUsername("root");
ds.setPassword("123456");
//2.创建对象
JdbcTemplate jt = new JdbcTemplate();
//3.给对象设置数据源
jt.setDataSource(ds);
//3.执行操作
jt.execute("insert into account(name,money)values('SSS',2222)");
}
}