Spring整合JDBC
1 Spring提供了很多持久层技术模板类
ORM持久化技术 模板类
JDBC org.springframework.jdbc.core.JdbcTemplate
Hibernate3.0 org.springframework.orm.hibernate3.HibernateTemplate
IBatis(MyBatis) org.springframework.orm.ibatis.SqlMapClientTemplate
JPA org.springframework.orm.jpa.JpaTemplate
2 Spring与Jdbc
(1)原生JDBC模板
<1>连接池的使用
1.使用C3p0连接池(com.mchange.v2.c3p0.ComboPooledDataSource)
代码示例如下:
ComboPooledDataSource dataSource=new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql:///hibernate_crm");
dataSource.setUser("root");
dataSource.setPassword("root");
2.使用spring内置连接池(org.springframework.jdbc.datasource.DriverManagerDataSource)
代码示例如下:
DriverManagerDataSource dataSource=new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///hibernate_crm");
dataSource.setUsername("root");
dataSource.setPassword("root");
<2>JDBC模板对象的调用
//1 创建JDBC模板对象
JdbcTemplate jt=new JdbcTemplate();
//2连接进连接池
jt.setDataSource(dataSource);
//3 书写sql语句,并执行
String sql="insert into t_user values(null,'rose')";
jt.update(sql);
(2)Spring对连接池进行管理
<1>配置Spring内置的连接池DriverManagerDataSource
<bean name="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql:///hibernate_crm"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--配置JDBCTemplate对象并关联Spring内置的连接池 -->
<bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<2>配置C3P0连接池
导入jar包: com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql:///hibernate_crm"></property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--配置JDBCTemplate对象并关联C3p0连接池 -->
<bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<3>配置db连接池
导入jar包:
com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar
com.springsource.org.apache.commons.pool-1.5.3.jar
<!-- 配置 DBCP 连接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///spring_day02"/>
<property name="username" value="root"/>
<property name="password" value="123"/>
</bean>
(3)JdbcTemplate对象的增删改查
概述:JdbcTemplate的增删改都使用 update()方法。而查询则使用queryForObject()
//增
@Override
public void save(User u) {
String sql="insert into t_user values(null,?)";
jt.update(sql,u.getName());
}
//删(根据id删除)
@Override
public void delete(Integer id) {
String sql="delete from t_user where id=?";
jt.update(sql,id);
}
//改
@Override
public void update(User u) {
String sql="update t_user set name=? where id=?";
jt.update(sql,u.getName(),u.getId());
}
//查(根据id进行查询,获取一个对象)
@Override
public User getById(Integer id) {
String sql="select * from t_user where id=?";
User user = jt.queryForObject(sql, new RowMapper<User>() {
@Override
public User mapRow(ResultSet rs, int arg1) throws SQLException {
//封装实体 User对象返回给这个方法
User u=new User();
u.setId(rs.getInt("id"));
u.setName(rs.getString("name"));
return u;
}},id);
return user;
}
//查(查询表中总共有几条记录)
@Override
public int getTotalCount() {
String sql="select count(*) from t_user";
Integer count = jt.queryForObject(sql,Integer.class);
return count;
}
//查(查询获取表中的所以记录对象,获取的是集合对象)
@Override
public List<User> getAll() {
String sql="select * from t_user";
List<User> userList = jt.query(sql, new RowMapper<User>(){
@Override
public User mapRow(ResultSet rs, int arg1) throws SQLException {
User user=new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
return user;
}});
return userList;
}
(4)将数据库信息配置到属性文件中
<1>在src下创建一个配置文件,如 jdbc.properties
内容如下:
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///spring_crm
jdbc.username=root
jdbc.password=123
<2>在applicationContext主配置文件中
方式一:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties"/>
</bean>
方式二:
<context:property-placeholder location="classpath:jdbc.properties"/>
Spring事务管理
1事务回顾
<1>什么是事务:
事务逻辑上的一组操作,组成这组操作的各个逻辑单元,要么一起成功,要么一起失败.
<2>事务特性:
原子性 :强调事务的不可分割.
一致性 :事务的执行的前后数据的完整性保持一致.
隔离性 :一个事务执行的过程中,不应该受到其他事务的干扰
持久性 :事务一旦结束,数据就持久到数据库
<3>如果不考虑隔离性引发安全性问题:
脏读 :一个事务读到了另一个事务的未提交的数据
不可重复读 :一个事务读到了另一个事务已经提交的 update 的数据导致多次查询结果不一致.
虚幻读 :一个事务读到了另一个事务已经提交的 insert 的数据导致多次查询结果不一致.
<4>解决读问题: 设置事务隔离级别
未提交读 :脏读,不可重复读,虚读都有可能发生
已提交读 :避免脏读。但是不可重复读和虚读有可能发生
可重复读 :避免脏读和不可重复读.但是虚读有可能发生.
串行化的 :避免以上所有读问题.
<5>
Mysql 默认:可重复读
Oracle 默认:读已提交
2 相关的API接口
(1) 平台事务管理器 PlatformTransactionManager
<1> org.springframework.jdbc.datasource.DataSourceTransactionManager
SpringJDBC 或 iBatis 使用
<2> org.springframework.orm.hibernate3.HibernateTransactionManager
Hibernate 进行持久化数据时使用
(2)事务定义信息接口 TransactionDefinition
事务定义信息内容包括:
* 隔离级别
* 传播行为
事务的传播的格式为:PROPAGION_XXX
& 保证同一个事务中
PROPAGATION_REQUIRED 支持当前事务,如果不存在 就新建一个(默认)
PROPAGATION_SUPPORTS 支持当前事务,如果不存在,就不使用事务
PROPAGATION_MANDATORY 支持当前事务,如果不存在,抛出异常
& 保证不在同一个事务中
PROPAGATION_REQUIRES_NEW 如果有事务存在,挂起当前事务,创建一个新的事务
PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果有事务存在,挂起当前事务
PROPAGATION_NEVER 以非事务方式运行,如果有事务存在,抛出异常
PROPAGATION_NESTED 如果当前事务存在,则嵌套事务执行
* 超时信息
* 是否只读
(3) 事务状态接口 TransactionStatus,记录事务的状态
2 Spring事务管理过程简述
平台事务管理器(PlatformTransactionManager)
根据 事务定义的信息(TransactionDefinition )
将事务管理过程中的状态记录到 TransactionStatus里面
3 Spring事务管理分类
(1)传统的事务管理方式:编程式事务方式(手动编写代码完成事务的管理)
<1> Jdbc相关代码示例:
(Connection) conn.setAutoCommit(false); //设置手动管理事务
<2>Hibernate相关代码示例:
Session.beginTransaction();
<3>特点分析:
优点:细粒度的事务控制,可以对指定方法,或指定方法的某几行进行事务控制。
缺点:虽灵活,但繁琐,每次要开启 ,提交,回滚,且要释放资源,否则耗内存。
(2)Spring提供对事务的管理,这就叫做声明式事务管理。
<1>声明式事务管理特点:
粗粒度的事务控制,只能给整个方法应用事务,不可以对方法的某几行应用事务。
其核心是基于 AOP的。
<2>Spring声明式事务管理器分类:
Jdbc技术:DataSourceTransactionManager
Hibernate技术:HibernateTransactionManager
<3>xml声明式事务管理配置如下:
《1》<!--配置spring的事务核心管理器,封装了所有事务操作,依赖于连接池 -->
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager ">
<property name="dataSource" ref="dataSource"></property>
</bean>
《2》<!--配置spring事务模板对象,用于service层代码API调用,依赖于spring的事务核心管理器 -->
<bean name="transcationTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"></property>
</bean>
《3》将spring事务模板对象 依赖到service层中
<bean name="accountService" class="cn.sss.service.AccountServiceImp">
<property name="ad" ref="accountDao"></property>
<property name="tt" ref="transcationTemplate"></property>
</bean>
《4》<!-- 配置事务通知 ,依赖spring事务核心管理器-->
<tx:advice transaction-manager="transactionManager" id="txAdvice">
<tx:attributes>
<!--以方法为单位,指定方法应用什么事务属性
name:要进行事务管理 的方法名
isolation:设置事务的隔离级别
propagation:事务的传播行为
read-only:只读
-->
<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
<!--下面为企业中的事务管理 的方法配置(使用通配符 *) -->
<tx:method name="persist*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
<tx:method name="update*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
<tx:method name="modify*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
<tx:method name="delete*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
<tx:method name="remove*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
<tx:method name="get*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true"/>
<tx:method name="find*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true"/>
<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
</tx:attributes>
</tx:advice>
《5》<!--配置织入(把事务通知织入到目标对象中) -->
<aop:config>
<!--配置切点(需增强的方法) -->
<aop:pointcut expression="execution(* cn.itheima.service.*ServiceImp.*(..))" id="txPc"/>
<!-- 配置切面(切点+通知)
advice-ref:通知名称
pointcut-ref:切点名称
-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPc"/>
</aop:config>
<4>注解 实现spring声明式事务管理
* 主配置文件为:
<!--配置spring的事务核心管理器,封装了所有事务操作,依赖于连接池 -->
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager ">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置spring事务模板对象,依赖于spring的事务核心管理器 -->
<bean name="transcationTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"></property>
</bean>
<!--开启使用注解管理aop事务 -->
<tx:annotation-driven/>
* 业务service层:
& 在类上方使用注解 注入aop事务管理的配置,作用于整个类中所有的方法
@Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED,readOnly=false)
public class AccountServiceImp implements AccountService {}
& 在方法名前使用注解配置aop事务(作用于此方法,权限大于在类上写入的注解)
@Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED,readOnly=false)
public void transfer(Integer from, Integer to, Double money) {}