spring第四天笔记
一、内容介绍
1、jdbcTemplate的使用
2、spring的事务控制
二、jdbcTemplate的使用
1、jdbcTemplate的介绍
Spring对数据库的操作在jdbc上面做了深层次的封装,使用spring的注入功能,可以把DataSource注册到JdbcTemplate之中。
jdbc — dbutils – jdbcTemplate(spring 提供) – mybatis(主流) – spring data jpa(趋势)
2、数据源配置
a. c3p0数据源
<!--c3p0数据源-->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!--配置c3p0数据源-->
<bean id="c3p0DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
b. dbcp 数据源
<!--dbcp数据源-->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<bean id="dbcpDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
c. spring jdbc 自带数据源,包含了JdbcTemplate对象
<!--spring自带数据源-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<bean id="springDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
3、jdbcTemplate的CRUD
/**
* 查询使用:query
* 增删改:update
*
* queryForList :查询返回一个List集合,Map集合
* query(sql ,属性与列的映射对象,参数):返回值:List<pojo>
* queryForObject :针对于返回一个对象
* update(sql ,参数):执行增删改操作
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestJdbcTemplate {
@Autowired
JdbcTemplate jdbcTemplate;
@Test
public void testFindAll(){
String sql = "select * from account";
// 方法返回值是List集合,list中是map集合
List<Map<String, Object>> accountList = jdbcTemplate.queryForList(sql);
// for (Map<String, Object> map : accountList) {
// System.out.println(map);
// }
List<Account> accountList = jdbcTemplate.query(sql, new AccountRowMapper());
// for (Account account : accountList) {
// System.out.println(account);
// }
}
@Test
public void testFindById(){
String sql = "select * from account where id = ?";
List<Account> accountList = jdbcTemplate.query(sql, new AccountRowMapper(), 5);
// System.out.println(accountList.size() == 1 ?accountList.get(0):"结果为null");
// queryForObject(SQL语句,列与属性的映射,参数):掌握
Account account = jdbcTemplate.queryForObject(sql, new AccountRowMapper(), 5);
// System.out.println(account);
}
@Test
public void testSave(){
String sql = "insert into account values(null , ? ,?)";
jdbcTemplate.update(sql ,"zhangsan", 10000);
}
@Test
public void testUpdate(){
String sql = "update account set money = ?, name = ? where id = ?";
jdbcTemplate.update(sql ,1000,"lisi",4);
}
@Test
public void testDel(){
String sql = "delete from account where id = ?";
jdbcTemplate.update(sql , 4);
}
@Test
public void testGetTotalCount(){
String sql = "select count(*) from account";
// queryForObject(sql语句, 返回值类型)
Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
System.out.println(count);
}
}
映射关系(实现列名属性名不一致的映射类)
public class AccountRowMapper implements RowMapper<Account> {
/**
* @param rs 结果集对象,只包含一行数据
* @param rowNum
* @return
* @throws SQLException
*/
@Override
public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
Account account = new Account();
int id = rs.getInt("id");
account.setId(id);
account.setName(rs.getString("name"));
account.setMoney(rs.getFloat("money"));
return account;
}
}
4、在dao中使用jdbcTemplate方法一
a. applicationContext.xml
<!--创建jdbcTemplate模板对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="springDataSource"></property>
</bean>
b.在dao层中使用模板对象
@Repository
public class AccountDaoImpl implements AccountDao {
//自动注入模板对象
@Autowired
JdbcTemplate jdbcTemplate;
}
5、在dao中使用jdbcTemplate方法二(了解)
a. 在dao实现类中继承接口JdbcDaoSupport类
public class AccountDaoImpl2 extends JdbcDaoSupport implements AccountDao
b.所有的dao对象需要在xml中创建,需要通过set方法注入数据源对象
<!--创建dao层对象-->
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl2">
<!--通过set方法注入数据源-->
<property name="dataSource" ref="springDataSource"></property>
</bean>
三、spring的事务控制
1、spring事务控制的api介绍–事务管理类
org.springframework.orm.hibernate5.HibernateTransactionManager
: 在hibernate环境下使用
rg.springframework.jdbc.datasource.DataSourceTransactionManager
: 在jdbcTemplate,mybatis(ibatis)环境下使用
2、事务的特性
a、事务的四个特性
原子性: 是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
隔离性: 多个用户并发访问数据库时,一个用户的事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。
一致性: 事务前后数据的完整性必须保持一致。要么全部完成,要么全部不完成。
持久性: 一旦提交持久化到数据中
b、隔离级别
读未提交:read uncommited
产生的问题:脏读,幻读,不可重复读
脏读:读到了未提交的数据
不可重复读:一个事务读到了另一个事务已经提交(update)的数据。引发另一个事务,在事务中的多次查询结果不一致。
幻读(虚读):一个事务读到了另一个事务已经提交(insert)的数据。导致另一个事务,在事务中多次查询的结果不一致。
读已提交:read commited
产生的问题:幻读,不可重复读
解决的问题:脏读
重复读: repeatable read
产生的问题:幻读
解决的问题:脏读,不可重复读
串行化(序列化): serializable
产生的问题:null
解决的问题: 所有的问题
隔离级别最高,效率最低
c、数据库的支持的隔离级别 – 一般情况下选择都是默认的隔离级别
mysql支持:
read uncommited
read commited
repeatable read
serializable
默认的隔离级别:repeatable read
Oracle支持:
read commited
serializable
read only(只读)
默认的隔离级别:read commited
3、事务的传播
a. 掌握
REQUIRED: 必要的: 如果没有事务,则新建一个事务,如果有事务,加入这个事务当中, spring指定为默认值
增删改
SUPPORTS: 支持的: 如果没有事务,非事务执行,如果有事务,加入这个事务当中
查询
b. 了解
MANDATORY: 可以使用当前的事务,如果没有事务,抛出异常
REQUERS_NEW: 新建一个事务,如果存在事务,则挂起事务
NOT_SUPPORTED: 必须非事务执行,如果有事务,则挂起事务
NEVER: 非事务执行,如果存在事务,抛出异常
NESTED: 有事务,嵌套执行,没有事务,执行REQUIRED
4、是否为只读的事务
a.如果是查询,则为只读的事务 readOnly = true
b.如果是增删改,则为非只读的事务,readOnly = false
5、基于xml声明式事务管理(配置文件)(重点)(推荐)
a. 编程式事务管理:在业务层写了事务技术代码
b. 声明式事务管理:在配置文件声明事务对象,管理事务,业务层中没有任何事务代码
- 引入依赖:
<!--aop的切面配置需要的jar包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<!--spring 的事务管理jar包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--spring 的基础包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--spring自带数据源, 包含了事务管理类 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
2.编写配置文件
<!--1、创建事务管理器对象-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源属性:事务存在连接中- 连接存在连接池(数据源)中-->
<property name="dataSource" ref="springDataSource"></property>
</bean>
<!--2、事务的增强: 过滤方法是否需要拦截
id:唯一的标识
transaction-manager:指定事务管理器
-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!--增强:方法的过滤-->
<tx:attributes>
<!--指定需要拦截的方法
isolation:隔离级别, 一般选择默认的
propagation:传播的行为,
read-only: 是否为只读的事务,增删改:非只读事务 read-only=false
查询:只读的事务:read-only=true
find* :通配符配置,只要以 find开头即可
-->
<!--配置方式一:全部配置-->
<!--增删改(取的都是默认值可以全部省略不写)-->
<tx:method name="insert*" />
<tx:method name="add*" />
<tx:method name="update*" />
<tx:method name="del*" />
<tx:method name="delete*" />
<tx:method name="save*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1"/>
<!--查询(不取默认值的写出来)-->
<tx:method name="find*" propagation="SUPPORTS" read-only="true" ></tx:method>
<tx:method name="select*" propagation="SUPPORTS" read-only="true" ></tx:method>
<tx:method name="query*" propagation="SUPPORTS" read-only="true"></tx:method>
<tx:method name="get*" isolation="DEFAULT" propagation="SUPPORTS" read-only="true" timeout="-1"></tx:method>
<!--配置方式二:one和theOrther-->
<tx:method name="find*" propagation="SUPPORTS" read-only="true"></tx:method>
<tx:method name="select*" propagation="SUPPORTS" read-only="true"></tx:method>
<tx:method name="query*" propagation="SUPPORTS" read-only="true"></tx:method>
<tx:method name="get*" propagation="SUPPORTS" read-only="true"></tx:method>
<!--其他方法的配置方法-->
<tx:method name="*" propagation="REQUIRED" read-only="false"></tx:method>
</tx:attributes>
</tx:advice>
<!--3、aop的配置:
切面= 切入点 +通知(增强)
-->
<aop:config>
<!--切面配置
advice-ref: 通知关联对象
pointcut: 切入点:
-->
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.itheima.service.impl.*.*(..))"></aop:advisor>
</aop:config>
- 业务层
业务层不需要任何事务管理,只需要提供业务代码即可
6、基于注解的配置(重点)
a. 引入依赖
与xml完全一致
b. 配置文件
1)配置事务管理类
<!--创建事务管理器对象-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源属性:事务存在连接中- 连接存在连接池(数据源)中-->
<property name="dataSource" ref="springDataSource"></property>
</bean>
2) 开启事务的注解管理
<!--transaction-manager: 关联事务管理器对象-->
<tx:annotation-driven transaction-manager="txManager"></tx:annotation-driven>
<!--开启aop的注解:自动代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
c. 业务层
出现接口上,表示该接口的所有实现类都有事务支持。
在类上标记注解:@Transactional,类中所有的方法都会使用事务管理
在方法上标记注解:@Transactional:只有该方法按照事务执行
以上三个位置的优先级:方法>类>接口
d.属性介绍
@Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, readOnly = false,timeout = -1)