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) {}