目录
1、spring中的JdbcTemplate[会用]
JdbcTemplate的作用
JdbcTemplate对象的创建
spring中配置数据源
在spring配置文件中配置 JdbcTemplate
最基本使用
使用xml文件
保存、更新、删除、查询操作
在dao中使用 JdbcTemplate
第二种方式:让dao继承 JdbcDaoSupport
2、Spring中的事务控制
Spring事务控制我们要明确的
Spring中事务控制的 API
PlatformTransactionManager
TransactionDefinition
TransactionStatus
基于XML的声明式事务控制(配置方式)重点
环境配置
配置步骤
基于注解的配置方式
环境配置
配置步骤
不使用 xml 的配置方式
它就是用于和数据库交互的,实现对表的CRUD操作
它是 spring 框架中提供的一个对象,是对原始 Jdbc API 对象的简单封装。spring 框架为我们提供了很多
的操作模板类。
操作关系型数据的:
JdbcTemplate
HibernateTemplate
操作 nosql 数据库的:
RedisTemplate
操作消息队列的:
JmsTemplate
我们今天的主角在 spring-jdbc-5.0.2.RELEASE.jar 中,我们在导包的时候,除了要导入这个 jar 包
外,还需要导入一个 spring-tx-5.0.2.RELEASE.jar(它是和事务相关的)。
我们可以参考它的源码,来一探究竟:
public JdbcTemplate() {
}
public JdbcTemplate(DataSource dataSource) {
setDataSource(dataSource);
afterPropertiesSet();
}
public JdbcTemplate(DataSource dataSource, boolean lazyInit) {
setDataSource(dataSource);
setLazyInit(lazyInit);
afterPropertiesSet();
}
除了默认构造函数之外,都需要提供一个数据源。既然有set方法,依据我们之前学过的依赖注入,我们可以
在配置文件中配置这些对象。
/**
* JdbcTemplate的最基本用法
*/
public class JdbcTemplateDemo1 {
public static void main(String[] args) {
//准备数据源:spring的内置数据源
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/eesy");
ds.setUsername("root");
ds.setPassword("1234");
//1.创建JdbcTemplate对象
JdbcTemplate jt = new JdbcTemplate();
//给jt设置数据源
jt.setDataSource(ds);
//2.执行操作
jt.execute("insert into account(name,money)values('ccc',1000)");
}
}
public class JdbcTemplateDemo2 {
public static void main(String[] args) {
//1.获取容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.获取对象
JdbcTemplate jt = ac.getBean("jdbcTemplate",JdbcTemplate.class);
//3.执行操作
jt.execute("insert into account(name,money)values('ddd',2222)");
}
}
/**
* JdbcTemplate的CRUD操作
*/
public class JdbcTemplateDemo3 {
public static void main(String[] args) {
//1.获取容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.获取对象
JdbcTemplate jt = ac.getBean("jdbcTemplate",JdbcTemplate.class);
//3.执行操作
//保存
// 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 accounts = jt.query("select * from account where money > ?",new AccountRowMapper(),1000f);
// List accounts = jt.query("select * from account where money > ?",new BeanPropertyRowMapper(Account.class),1000f);
// for(Account account : accounts){
// System.out.println(account);
// }
//查询一个
// List accounts = jt.query("select * from account where id = ?",new BeanPropertyRowMapper(Account.class),1);
// System.out.println(accounts.isEmpty()?"没有内容":accounts.get(0));
//查询返回一行一列(使用聚合函数,但不加group by子句)
Long count = jt.queryForObject("select count(*) from account where money > ?",Long.class,1000f);
System.out.println(count);
}
}
/**
* 定义Account的封装策略
*/
class AccountRowMapper implements RowMapper{
/**
* 把结果集中的数据封装到Account中,然后由spring把每个Account加到集合中
* @param rs
* @param rowNum
* @return
* @throws SQLException
*/
@Override
public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
Account account = new Account();
account.setId(rs.getInt("id"));
account.setName(rs.getString("name"));
account.setMoney(rs.getFloat("money"));
return account;
}
}
public class JdbcTemplateDemo4 {
public static void main(String[] args) {
//1.获取容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.获取对象
IAccountDao accountDao = ac.getBean("accountDao",IAccountDao.class);
Account account = accountDao.findAccountById(1);
System.out.println(account);
account.setMoney(30000f);
accountDao.updateAccount(account);
}
}
/**
* 账户的持久层实现类
*/
@Repository
public class AccountDaoImpl2 implements IAccountDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public Account findAccountById(Integer accountId) {
List accounts = jdbcTemplate.query("select * from account where id = ?",new BeanPropertyRowMapper(Account.class),accountId);
return accounts.isEmpty()?null:accounts.get(0);
}
@Override
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);
}
@Override
public void updateAccount(Account account) {
jdbcTemplate.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
}
}
有个小问题。就是我们的 dao 有很多时,每个 dao 都有一些重复性的代码。下面就是重复代码:
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
/**
* 账户的持久层实现类
*/
public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao {
@Override
public Account findAccountById(Integer accountId) {
List accounts = super.getJdbcTemplate().query("select * from account where id = ?",new BeanPropertyRowMapper(Account.class),accountId);
return accounts.isEmpty()?null:accounts.get(0);
}
@Override
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);
}
@Override
public void updateAccount(Account account) {
super.getJdbcTemplate().update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
}
}
思考:
两版 Dao 有什么区别呢?
答案:
在 第一种在 Dao 类中定义 JdbcTemplate 的方式,适用于所有配置方式(xml 和注解都可以)。
让 第二种让 Dao 继承 JdbcDaoSupport 的方式,只能用于基于 XML 的方式,注解用不了。
第一:JavaEE 体系进行分层开发,事务处理位于业务层,Spring 提供了分层设计 业务层的事务处理解决方案。
第二:spring 框架为我们提供了一组事务控制的接口。具体在后面的第二小节介绍。这组接口是在spring-tx-5.0.2.RELEASE.jar 中。
第三:spring 的事务控制都是基于 AOP 的,它既可以使用编程的方式实现,也可以使用配置的方式实现。我们学习的重点是使用配置的方式实现。
事务的隔离级别
事务的传播行为
REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值)
SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)
MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常
REQUERS_NEW:新建事务,如果当前在事务中,把当前事务挂起。
NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
NEVER:以非事务方式运行,如果当前存在事务,抛出异常
NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作
超时时间
默认值是-1,没有超时限制。如果有,以秒为单位进行设置。
是否是只读事务
建议查询时设置为只读。
org.springframework
spring-context
5.0.2.RELEASE
org.springframework
spring-jdbc
5.0.2.RELEASE
org.springframework
spring-tx
5.0.2.RELEASE
org.springframework
spring-test
5.0.2.RELEASE
mysql
mysql-connector-java
5.1.6
org.aspectj
aspectjweaver
1.8.7
junit
junit
4.12
org.springframework
spring-context
5.0.2.RELEASE
org.springframework
spring-jdbc
5.0.2.RELEASE
org.springframework
spring-tx
5.0.2.RELEASE
org.springframework
spring-test
5.0.2.RELEASE
mysql
mysql-connector-java
5.1.6
org.aspectj
aspectjweaver
1.8.7
junit
junit
4.12
@Configuration
@EnableTransactionManagement
public class SpringTxConfiguration {
//里面配置数据源,配置 JdbcTemplate,配置事务管理器。在之前的步骤已经写过了。
}