专栏首页海仔技术驿站SSH框架之Spring第四篇

SSH框架之Spring第四篇

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/zhao1299002788/article/details/101168019

1.1 JdbcTemplate概述 : 
		它是spring框架中提供的一个对象,是对原始JdbcAPI对象的简单封装.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.
	在导包的时候需要导入spring-jdbc-4.24.RELEASF.jar,还需要导入一个spring-tx-4.2.4.RELEASE.jar(它和事务有关)

	<!-- 配置数据源 -->
		<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
			<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
			<property name="url" value="jdbc:mysql:// /spring_day04"></property>
			<property name="username" value="root"></property>
			<property name="password" value="1234"></property>
		</bean>
	1.3.3.3配置spring内置数据源
		spring框架也提供了一个内置数据源,我们也可以使用spring的内置数据源,它就在spring-jdbc-4.2.4.REEASE.jar包中:
		<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
			<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
			<property name="url" value="jdbc:mysql:///spring_day04"></property>
			<property name="username" value="root"></property>
			<property name="password" value="1234"></property>
		</bean>
	1.3.4将数据库连接的信息配置到属性文件中:
		【定义属性文件】
		jdbc.driverClass=com.mysql.jdbc.Driver
		jdbc.url=jdbc:mysql:///spring_day02
		jdbc.username=root
		jdbc.password=123
		【引入外部的属性文件】
		一种方式:
			<!-- 引入外部属性文件: -->
			<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
				<property name="location" value="classpath:jdbc.properties"/>
			</bean>

		二种方式:
		<context:property-placeholder location="classpath:jdbc.properties"/>

	1.4JdbcTemplate的增删改查操作
		1.4.1前期准备
		创建数据库:
		create database spring_day04;
		use spring_day04;
		创建表:
		create table account(
			id int primary key auto_increment,
			name varchar(40),
			money float
		)character set utf8 collate utf8_general_ci;
	1.4.2在spring配置文件中配置JdbcTemplate
		<?xml version="1.0" encoding="UTF-8"?>
		<beans xmlns="http://www.springframework.org/schema/beans"
				xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
				xsi:schemaLocation="http://www.springframework.org/schema/beans 
				http://www.springframework.org/schema/beans/spring-beans.xsd">

			<!-- 配置一个数据库的操作模板:JdbcTemplate -->
			<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
				<property name="dataSource" ref="dataSource"></property>
			</bean>
			
			<!-- 配置数据源 -->
			<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
			<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
			<property name="url" value="jdbc:mysql:///spring_day04"></property>
			<property name="username" value="root"></property>
			<property name="password" value="1234"></property>
		</bean>
		</beans>
	1.4.3最基本使用
		public class JdbcTemplateDemo2 {
			public static void main(String[] args) {
				//1.获取Spring容器
				ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
				//2.根据id获取bean对象
				JdbcTemplate jt = (JdbcTemplate) ac.getBean("jdbcTemplate");
				//3.执行操作
				jt.execute("insert into account(name,money)values('eee',500)");
			}
		}
	1.4.4保存操作
		public class JdbcTemplateDemo3 {
			public static void main(String[] args) {

				//1.获取Spring容器
				ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
				//2.根据id获取bean对象
				JdbcTemplate jt = (JdbcTemplate) ac.getBean("jdbcTemplate");
				//3.执行操作
				//保存
				jt.update("insert into account(name,money)values(?,?)","fff",5000);
			}
		}
	1.4.5更新操作
		public class JdbcTemplateDemo3 {
			public static void main(String[] args) {

				//1.获取Spring容器
				ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
				//2.根据id获取bean对象
				JdbcTemplate jt = (JdbcTemplate) ac.getBean("jdbcTemplate");
				//3.执行操作
				//修改
				jt.update("update account set money = money-? where id = ?",300,6);
			}
		}
	1.4.6删除操作
		public class JdbcTemplateDemo3 {
			public static void main(String[] args) {

				//1.获取Spring容器
				ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
				//2.根据id获取bean对象
				JdbcTemplate jt = (JdbcTemplate) ac.getBean("jdbcTemplate");
				//3.执行操作
				//删除
				jt.update("delete from account where id = ?",6);
			}
		}
	1.4.7查询所有操作
		public class JdbcTemplateDemo3 {
			public static void main(String[] args) {

				//1.获取Spring容器
				ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
				//2.根据id获取bean对象
				JdbcTemplate jt = (JdbcTemplate) ac.getBean("jdbcTemplate");
				//3.执行操作
				//查询所有
				List<Account> accounts = jt.query("select * from account where money > ? ", 
													new AccountRowMapper(), 500);
				for(Account o : accounts){
					System.out.println(o);
				}
			}
		}

		public class AccountRowMapper implements RowMapper<Account>{
			@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;
			}
			
		}

	1.4.8查询一个操作
		使用RowMapper的方式:常用的方式
		public class JdbcTemplateDemo3 {
			public static void main(String[] args) {

				//1.获取Spring容器
				ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
				//2.根据id获取bean对象
				JdbcTemplate jt = (JdbcTemplate) ac.getBean("jdbcTemplate");
				//3.执行操作
				//查询一个
				List<Account> as = jt.query("select * from account where id = ? ", 
												new AccountRowMapper(), 55);
				System.out.println(as.isEmpty()?"没有结果":as.get(0));
			}
		}
	1.4.9查询返回一行一列操作
		public class JdbcTemplateDemo3 {
			public static void main(String[] args) {

				//1.获取Spring容器
				ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
				//2.根据id获取bean对象
				JdbcTemplate jt = (JdbcTemplate) ac.getBean("jdbcTemplate");
				//3.执行操作
				//查询返回一行一列:使用聚合函数,在不使用group by字句时,都是返回一行一列。最长用的就是分页中获取总记录条数
				Integer total = jt.queryForObject("select count(*) from account where money > ? ",Integer.class,500);
				System.out.println(total);
			}
		}
applicationContext.xml
		<?xml version="1.0" encoding="UTF-8"?>
		<beans xmlns="http://www.springframework.org/schema/beans"
			xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
			xmlns:context="http://www.springframework.org/schema/context"
			xmlns:aop="http://www.springframework.org/schema/aop"
			xmlns:tx="http://www.springframework.org/schema/tx"
			xsi:schemaLocation="http://www.springframework.org/schema/beans 
			http://www.springframework.org/schema/beans/spring-beans.xsd
			http://www.springframework.org/schema/context
			http://www.springframework.org/schema/context/spring-context.xsd
			http://www.springframework.org/schema/aop
			http://www.springframework.org/schema/aop/spring-aop.xsd
			http://www.springframework.org/schema/tx 
			http://www.springframework.org/schema/tx/spring-tx.xsd">

			<!-- 使用Spring管理连接池对象,Spring内置的连接池对象 -->
			
			<!-- <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
				<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
				<property name="url" value="jdbc:mysql:///spring_04"/>
				<property name="username" value="root"></property>
				<property name="password" value="root"></property>
			</bean> -->
			
			<!-- 配置数据源,使用Spring整合dbcp连接,没有导入jar包 -->
			<!-- <bean id="dataSource" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource">
				<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
				<property name="url" value="jdbc:mysql:///spring_04"/>
				<property name="username" value="root"/>
				<property name="password" value="root"/>
			</bean> -->
			
			<!-- 使用Spring整合c3p0的连接池,没有采用属性文件的方式 -->
			<!-- 
			<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
				<property name="driverClass" value="com.mysql.jdbc.Driver"/>
				<property name="jdbcUrl" value="jdbc:mysql:///spring_04"/>
				<property name="user" value="root"/>
				<property name="password" value="root"/>
			</bean> -->
			
			<!-- 使用context:property-placeholder标签,读取属性文件 -->
			<context:property-placeholder location="classpath:db.properties"/>
			
			<!-- 使用Spring整合c3p0的连接池,采用属性文件的方式 -->
			<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
				<property name="driverClass" value="${jdbc.driver}"/>
				<property name="jdbcUrl" value="${jdbc.url}"/>
				<property name="user" value="${jdbc.user}"/>
				<property name="password" value="${jdbc.password}"/>
				
			</bean>
			<!-- spring管理JbdcTemplate模板 -->
			<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
				<property name="dataSource" ref="dataSource"/>
			</bean>

		</beans>
db.properties : 属性文件
		jdbc.driver=com.mysql.jdbc.Driver
		jdbc.url=jdbc:mysql:///spring_day04
		jdbc.user=root
		jdbc.password=root
Demo测试 :
	package com.ithiema.demo1;

	import java.sql.ResultSet;
	import java.sql.SQLException;
	import java.util.List;

	import javax.annotation.Resource;

	import org.junit.Test;
	import org.junit.runner.RunWith;
	import org.springframework.jdbc.core.JdbcTemplate;
	import org.springframework.jdbc.core.RowMapper;
	import org.springframework.test.context.ContextConfiguration;
	import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

	/**
	 * Spring整合JdbcTemplate的方式入门
	 * @author Administrator
	 */
	@RunWith(SpringJUnit4ClassRunner.class)
	@ContextConfiguration("classpath:applicationContext.xml")
	public class Demo11 {
		
		@Resource(name="jdbcTemplate")
		private JdbcTemplate jdbcTemplate;
		
		/**
		 * 添加
		 */
		@Test
		public void run1(){
			jdbcTemplate.update("insert into account values (null,?,?)", "嘿嘿",10000);
		}
		
		/**
		 * 修改
		 */
		@Test
		public void run2(){
			jdbcTemplate.update("update account set name = ?,money = ? where id = ?", "嘻嘻",5000,6);
		}
		
		/**
		 * 删除
		 */
		@Test
		public void run3(){
			jdbcTemplate.update("delete from account where id = ?", 6);
		}
		
		/**
		 * 查询多条数据
		 */
		@Test
		public void run4(){
			// sql  		sql语句
			// rowMapper	提供封装数据的接口,自己提供实现类(自己封装数据的)
			List<Account> list = jdbcTemplate.query("select * from account", new BeanMapper());
			for (Account account : list) {
				System.out.println(account);
			}
		}	
	}

	/**
	 * 自己封装的实现类,封装数据的
	 * @author Administrator
	 */
	class BeanMapper implements RowMapper<Account>{
		
		/**
		 * 一行一行封装数据的
		 */
		public Account mapRow(ResultSet rs, int index) throws SQLException {
			// 创建Account对象,一个属性一个属性赋值,返回对象
			Account ac = new Account();
			ac.setId(rs.getInt("id"));
			ac.setName(rs.getString("name"));
			ac.setMoney(rs.getDouble("money"));
			return ac;
		}
		
	}

2,1 Spring 事务控制我们要明确的
	1: JavaEE体系进行分层开发,事务处理位于业务层,Spring提供了分层设计业务层的事务处理解决方案.
	2: Spring框架为我们提供就一组事务控制的接口.这组接口是在spring-tx-4.2.4RELEASE.jar中.
	3: spring的事务都是基于AOP的,它既可以使用编程的方式实现,也可以使用配置的方式实现
	2.2Spring中事务控制的API介绍
		2.2.1PlatformTransactionManager
		此接口是spring的事务管理器,它里面提供了我们常用的操作事务的方法,如下图:

		我们在开发中都是使用它的实现类,如下图:

		真正管理事务的对象
		org.springframework.jdbc.datasource.DataSourceTransactionManager	使用Spring JDBC或iBatis 进行持久化数据时使用
		org.springframework.orm.hibernate3.HibernateTransactionManager		使用Hibernate版本进行持久化数据时使用
	2.2.2TransactionDefinition
		它是事务的定义信息对象,里面有如下方法:

	2.2.2.1事务的隔离级别

	2.2.2.2事务的传播行为
		REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值)
		SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)
		MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常
		REQUERS_NEW:新建事务,如果当前在事务中,把当前事务挂起。
		NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
		NEVER:以非事务方式运行,如果当前存在事务,抛出异常
		NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行REQUIRED类似的操作。
		2.2.2.3超时时间
		默认值是-1,没有超时限制。如果有,以秒为单位进行设置。
		2.2.2.4是否是只读事务
		建议查询时设置为只读。
		2.2.3TransactionStatus
		此接口提供的是事务具体的运行状态,方法介绍如下图:

	2.3基于XML的声明式事务控制(配置方式)重点
		2.3.1环境搭建
		2.3.1.1第一步:拷贝必要的jar包到工程的lib目录

	2.3.1.2第二步:创建spring的配置文件并导入约束
		<?xml version="1.0" encoding="UTF-8"?>
		<beans xmlns="http://www.springframework.org/schema/beans"
				xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
				xmlns:aop="http://www.springframework.org/schema/aop"
			 xmlns:tx="http://www.springframework.org/schema/tx"
				xsi:schemaLocation="http://www.springframework.org/schema/beans 
						http://www.springframework.org/schema/beans/spring-beans.xsd
						http://www.springframework.org/schema/tx 
						http://www.springframework.org/schema/tx/spring-tx.xsd
						http://www.springframework.org/schema/aop 
						http://www.springframework.org/schema/aop/spring-aop.xsd">	
		</beans>
		2.3.1.3第三步:准备数据库表和实体类
		创建数据库:
		create database spring_day04;
		use spring_day04;
		创建表:
		create table account(
			id int primary key auto_increment,
			name varchar(40),
			money float
		)character set utf8 collate utf8_general_ci;
		/**
		 * 账户的实体
		 */
		public class Account implements Serializable {

			private Integer id;
			private String name;
			private Float money;
			public Integer getId() {
				return id;
			}
			public void setId(Integer id) {
				this.id = id;
			}
			public String getName() {
				return name;
			}
			public void setName(String name) {
				this.name = name;
			}
			public Float getMoney() {
				return money;
			}
			public void setMoney(Float money) {
				this.money = money;
			}
			@Override
			public String toString() {
				return "Account [id=" + id + ", name=" + name + ", money=" + money + "]";
			}
		}
		2.3.1.4第四步:编写业务层接口和实现类
		/**
		 * 账户的业务层接口
		 */
		public interface IAccountService {
			
			/**
			 * 根据id查询账户信息
			 * @param id
			 * @return
			 */
			Account findAccountById(Integer id);//查
			
			/**
			 * 转账
			 * @param sourceName	转出账户名称
			 * @param targeName		转入账户名称
			 * @param money			转账金额
			 */
			void transfer(String sourceName,String targeName,Float money);//增删改
		}

		/**
		 * 账户的业务层实现类
		 */
		public class AccountServiceImpl implements IAccountService {
			
			private IAccountDao accountDao;
			
			public void setAccountDao(IAccountDao accountDao) {
				this.accountDao = accountDao;
			}

			@Override
			public Account findAccountById(Integer id) {
				return accountDao.findAccountById(id);
			}

			@Override
			public void transfer(String sourceName, String targeName, Float money) {
				//1.根据名称查询两个账户
				Account source = accountDao.findAccountByName(sourceName);
				Account target = accountDao.findAccountByName(targeName);
				//2.修改两个账户的金额
				source.setMoney(source.getMoney()-money);//转出账户减钱
				target.setMoney(target.getMoney()+money);//转入账户加钱
				//3.更新两个账户
				accountDao.updateAccount(source);
				int i=1/0;
				accountDao.updateAccount(target);
			}
		}
		2.3.1.5第五步:编写Dao接口和实现类
		/**
		 * 账户的持久层接口
		 */
		public interface IAccountDao {
			
			/**
			 * 根据id查询账户信息
			 * @param id
			 * @return
			 */
			Account findAccountById(Integer id);

			/**
			 * 根据名称查询账户信息
			 * @return
			 */
			Account findAccountByName(String name);
			
			/**
			 * 更新账户信息
			 * @param account
			 */
			void updateAccount(Account account);
		}
		/**
		 * 账户的持久层实现类
		 * 此版本dao,只需要给它的父类注入一个数据源
		 */
		public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao {

			@Override
			public Account findAccountById(Integer id) {
				List<Account> list = getJdbcTemplate().query("select * from account where id = ? ",new AccountRowMapper(),id);
				return list.isEmpty()?null:list.get(0);
			}

			@Override
			public Account findAccountByName(String name) {
				List<Account> list =  getJdbcTemplate().query("select * from account where name = ? ",new AccountRowMapper(),name);
				if(list.isEmpty()){
					return null;
				}
				if(list.size()>1){
					throw new RuntimeException("结果集不唯一,不是只有一个账户对象");
				}
				return list.get(0);
			}

			@Override
			public void updateAccount(Account account) {
				getJdbcTemplate().update("update account set money = ? where id = ? ",account.getMoney(),account.getId());
			}
		}

		/**
		 * 账户的封装类RowMapper的实现类
		 */
		public class AccountRowMapper implements RowMapper<Account>{

			@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;
			}
		}
		2.3.1.6第六步:在配置文件中配置业务层和持久层对
		<!-- 配置service -->
		<bean id="accountService" class="com.baidu.service.impl.AccountServiceImpl">
			<property name="accountDao" ref="accountDao"></property>
		</bean>
			
		<!-- 配置dao -->
		<bean id="accountDao" class="com.baidu.dao.impl.AccountDaoImpl">
			<!-- 注入dataSource -->
			<property name="dataSource" ref="dataSource"></property>
		</bean>
			
		<!-- 配置数据源 -->
		<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
			<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
			<property name="url" value="jdbc:mysql:///spring_day04"></property>
			<property name="username" value="root"></property>
			<property name="password" value="1234"></property>
		</bean>
	2.3.2配置步骤
		2.3.2.1第一步:配置事务管理器
		<!-- 配置一个事务管理器 -->
		<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
			<!-- 注入DataSource -->
			<property name="dataSource" ref="dataSource"></property>
		</bean>
		2.3.2.2第二步:配置事务的通知引用事务管理器
		<!-- 事务的配置 -->
		<tx:advice id="txAdvice" transaction-manager="transactionManager">
		</tx:advice>
		2.3.2.3第三步:配置事务的属性
		<!--在tx:advice标签内部 配置事务的属性 -->
		<tx:attributes>
		<!-- 指定方法名称:是业务核心方法 
			read-only:是否是只读事务。默认false,不只读。
			isolation:指定事务的隔离级别。默认值是使用数据库的默认隔离级别。 
			propagation:指定事务的传播行为。
			timeout:指定超时时间。默认值为:-1。永不超时。
			rollback-for:用于指定一个异常,当执行产生该异常时,事务回滚。产生其他异常,事务不回滚。没有默认值,任何异常都回滚。
			no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时,事务回滚。没有默认值,任何异常都回滚。
			-->
			<tx:method name="*" read-only="false" propagation="REQUIRED"/>
			<tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
		</tx:attributes>
		2.3.2.4第四步:配置AOP-切入点表达式
		<!-- 配置aop -->
		<aop:config>
			<!-- 配置切入点表达式 -->
			<aop:pointcut expression="execution(* com.baidu.service.impl.*.*(..))" id="pt1"/>
		</aop:config>
		2.3.2.5第五步:配置切入点表达式和事务通知的对应关系
		<!-- 在aop:config标签内部:建立事务的通知和切入点表达式的关系 -->
		<aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"/>
		2.4基于XML和注解组合使用的整合方式
		2.4.1环境搭建
		2.4.1.1第一步:拷贝必备的jar包到工程的lib目录

		2.4.1.2第二步:创建spring的配置文件导入约束并配置扫描的包
		<?xml version="1.0" encoding="UTF-8"?>
		<beans xmlns="http://www.springframework.org/schema/beans"
					xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
					xmlns:aop="http://www.springframework.org/schema/aop"
					xmlns:tx="http://www.springframework.org/schema/tx"
					xmlns:context="http://www.springframework.org/schema/context"
					xsi:schemaLocation="http://www.springframework.org/schema/beans 
						http://www.springframework.org/schema/beans/spring-beans.xsd
							http://www.springframework.org/schema/tx 
							http://www.springframework.org/schema/tx/spring-tx.xsd
							http://www.springframework.org/schema/aop 
							http://www.springframework.org/schema/aop/spring-aop.xsd
							http://www.springframework.org/schema/context
						http://www.springframework.org/schema/context/spring-context.xsd">
			<!-- 配置spring要扫描的包 -->
			<context:component-scan base-package="com.baidu"></context:component-scan>
		</beans>
	2.4.1.3第三步:创建数据库表和实体类
		和基于xml的配置相同。
		2.4.1.4第四步:创建业务层接口和实现类并使用注解让spring管理
		业务层接口和基于xml配置的时候相同。略

		/**
		 * 账户的业务层实现类
		 */
		@Service("accountService")
		public class AccountServiceImpl implements IAccountService {
			@Autowired
			private IAccountDao accountDao;

			@Override
			public Account findAccountById(Integer id) {
				return accountDao.findAccountById(id);
			}

			@Override
			public void transfer(String sourceName, String targeName, Float money) {
				//1.根据名称查询两个账户
				Account source = accountDao.findAccountByName(sourceName);
				Account target = accountDao.findAccountByName(targeName);
				//2.修改两个账户的金额
				source.setMoney(source.getMoney()-money);//转出账户减钱
				target.setMoney(target.getMoney()+money);//转入账户加钱
				//3.更新两个账户
				accountDao.updateAccount(source);
				int i=1/0;
				accountDao.updateAccount(target);
			}
		}
	2.4.1.5第五步:创建Dao接口和实现类并使用注解让spring管理
		Dao层接口和AccountRowMapper与基于xml配置的时候相同。略

		@Repository("accountDao")
		public class AccountDaoImpl implements IAccountDao {

			@Autowired
			private JdbcTemplate jdbcTemplate;
			
			@Override
			public Account findAccountById(Integer id) {
				List<Account> list = jdbcTemplate.query("select * from account where id = ? ",new AccountRowMapper(),id);
				return list.isEmpty()?null:list.get(0);
			}

			@Override
			public Account findAccountByName(String name) {
				List<Account> list =  jdbcTemplate.query("select * from account where name = ? ",new AccountRowMapper(),name);
				if(list.isEmpty()){
					return null;
				}
				if(list.size()>1){
					throw new RuntimeException("结果集不唯一,不是只有一个账户对象");
				}
				return list.get(0);
			}

			@Override
			public void updateAccount(Account account) {
				jdbcTemplate.update("update account set money = ? where id = ? ",account.getMoney(),account.getId());
			}
		}
	2.4.2配置步骤
		2.4.2.1第一步:配置数据源和JdbcTemplate
		<!-- 配置数据源 -->
		<bean id="dataSource" 
					class="org.springframework.jdbc.datasource.DriverManagerDataSource">
			<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
			<property name="url" value="jdbc:mysql:///spring_day04"></property>
			<property name="username" value="root"></property>
			<property name="password" value="1234"></property>
		</bean>


	2.4.2.2第二步:配置事务管理器并注入数据源
		<!-- 配置JdbcTemplate -->
		<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
			<property name="dataSource" ref="dataSource"></property>
		</bean>
	2.4.2.3第三步:在业务层使用@Transactional注解
		@Service("accountService")
		@Transactional(readOnly=true,propagation=Propagation.SUPPORTS)
		public class AccountServiceImpl implements IAccountService {
			
			@Autowired
			private IAccountDao accountDao;

			@Override
			public Account findAccountById(Integer id) {
				return accountDao.findAccountById(id);
			}

			@Override
			@Transactional(readOnly=false,propagation=Propagation.REQUIRED)
			public void transfer(String sourceName, String targeName, Float money) {
				//1.根据名称查询两个账户
				Account source = accountDao.findAccountByName(sourceName);
				Account target = accountDao.findAccountByName(targeName);
				//2.修改两个账户的金额
				source.setMoney(source.getMoney()-money);//转出账户减钱
				target.setMoney(target.getMoney()+money);//转入账户加钱
				//3.更新两个账户
				accountDao.updateAccount(source);
				//int i=1/0;
				accountDao.updateAccount(target);
			}
		}

		该注解的属性和xml中的属性含义一致。该注解可以出现在接口上,类上和方法上。
		出现接口上,表示该接口的所有实现类都有事务支持。
		出现在类上,表示类中所有方法有事务支持
		出现在方法上,表示方法有事务支持。
		以上三个位置的优先级:方法>类>接口
	2.4.2.4第四步:在配置文件中开启spring对注解事务的支持
		<!-- 开启spring对注解事务的支持 -->
		<tx:annotation-driven transaction-manager="transactionManager"/> 
		2.5基于纯注解的声明式事务控制(配置方式)重点
		2.5.1环境搭建
		2.5.1.1第一步:拷贝必备的jar包到工程的lib目录

		2.5.1.2第二步:创建一个类用于加载spring的配置并指定要扫描的包
		/**
		 * 用于初始化spring容器的配置类
		 */
		@Configuration
		@ComponentScan(basePackages="com.baidu")
		public class SpringConfiguration {

		}
    2.5.1.3第三步:创建数据库表和实体类
		和基于xml的配置相同。略
	2.5.1.4第四步:创建业务层接口和实现类并使用注解让spring管理
		业务层接口和基于xml配置的时候相同。略

		/**
		 * 账户的业务层实现类
		 */
		@Service("accountService")
		public class AccountServiceImpl implements IAccountService {
			@Autowired
			private IAccountDao accountDao;

			@Override
			public Account findAccountById(Integer id) {
				return accountDao.findAccountById(id);
			}

			@Override
			public void transfer(String sourceName, String targeName, Float money) {
				//1.根据名称查询两个账户
				Account source = accountDao.findAccountByName(sourceName);
				Account target = accountDao.findAccountByName(targeName);
				//2.修改两个账户的金额
				source.setMoney(source.getMoney()-money);//转出账户减钱
				target.setMoney(target.getMoney()+money);//转入账户加钱
				//3.更新两个账户
				accountDao.updateAccount(source);
				int i=1/0;
				accountDao.updateAccount(target);
			}
		}

	2.5.1.5第五步:创建Dao接口和实现类并使用注解让spring管理
		Dao层接口和AccountRowMapper与基于xml配置的时候相同。略

		@Repository("accountDao")
		public class AccountDaoImpl implements IAccountDao {

			@Autowired
			private JdbcTemplate jdbcTemplate;
			
			@Override
			public Account findAccountById(Integer id) {
				List<Account> list = jdbcTemplate.query("select * from account where id = ? ",new AccountRowMapper(),id);
				return list.isEmpty()?null:list.get(0);
			}

			@Override
			public Account findAccountByName(String name) {
				List<Account> list =  jdbcTemplate.query("select * from account where name = ? ",new AccountRowMapper(),name);
				if(list.isEmpty()){
					return null;
				}
				if(list.size()>1){
					throw new RuntimeException("结果集不唯一,不是只有一个账户对象");
				}
				return list.get(0);
			}

			@Override
			public void updateAccount(Account account) {
				jdbcTemplate.update("update account set money = ? where id = ? ",account.getMoney(),account.getId());
			}
		}

	2.5.2配置步骤
		2.5.2.1第一步:使用@Bean注解配置数据源
		@Bean(name = "dataSource")
			public DataSource createDS() throws Exception {
				DriverManagerDataSource dataSource = new DriverManagerDataSource();
				dataSource.setUsername("root");
				dataSource.setPassword("123");
				dataSource.setDriverClassName("com.mysql.jdbc.Driver");
				dataSource.setUrl("jdbc:mysql:///spring3_day04");
				return dataSource;
			}
	2.5.2.2第二步:使用@Bean注解配置配置事务管理器
		@Bean
		public PlatformTransactionManager 
				createTransactionManager(@Qualifier("dataSource") DataSource dataSource) {
			return new DataSourceTransactionManager(dataSource);
		}
		2.5.2.3第三步:使用@Bean注解配置JdbcTemplate
		@Bean
		public JdbcTemplate createTemplate(@Qualifier("dataSource") DataSource dataSource) 
		{
			return new JdbcTemplate(dataSource);
		}
	2.5.2.4第四步:在需要控制事务的业务层实现类上使用@Transactional注解
		@Service("accountService")
		@Transactional(readOnly=true,propagation=Propagation.SUPPORTS)
		public class AccountServiceImpl implements IAccountService {
			
			@Autowired
			private IAccountDao accountDao;

			@Override
			public Account findAccountById(Integer id) {
				return accountDao.findAccountById(id);
			}

			@Override
			@Transactional(readOnly=false,propagation=Propagation.REQUIRED)
			public void transfer(String sourceName, String targeName, Float money) {
				//1.根据名称查询两个账户
				Account source = accountDao.findAccountByName(sourceName);
				Account target = accountDao.findAccountByName(targeName);
				//2.修改两个账户的金额
				source.setMoney(source.getMoney()-money);//转出账户减钱
				target.setMoney(target.getMoney()+money);//转入账户加钱
				//3.更新两个账户
				accountDao.updateAccount(source);
				//int i=1/0;
				accountDao.updateAccount(target);
			}
		}

		该注解的属性和xml中的属性含义一致。该注解可以出现在接口上,类上和方法上。
		出现接口上,表示该接口的所有实现类都有事务支持。
		出现在类上,表示类中所有方法有事务支持
		出现在方法上,表示方法有事务支持。
		以上三个位置的优先级:方法>类>接口。
	2.5.2.5第五步:使用@EnableTransactionManagement开启spring对注解事务的的支持
		@Configuration
		@EnableTransactionManagement
		public class SpringTxConfiguration {
			//里面配置数据源,配置JdbcTemplate,配置事务管理器。在之前的步骤已经写过了。
		}

在Spring中开启事务的案例
	applicationContext3.xml	
		<?xml version="1.0" encoding="UTF-8"?>
		<beans xmlns="http://www.springframework.org/schema/beans"
			xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
			xmlns:context="http://www.springframework.org/schema/context"
			xmlns:aop="http://www.springframework.org/schema/aop"
			xmlns:tx="http://www.springframework.org/schema/tx"
			xsi:schemaLocation="http://www.springframework.org/schema/beans 
			http://www.springframework.org/schema/beans/spring-beans.xsd
			http://www.springframework.org/schema/context
			http://www.springframework.org/schema/context/spring-context.xsd
			http://www.springframework.org/schema/aop
			http://www.springframework.org/schema/aop/spring-aop.xsd
			http://www.springframework.org/schema/tx 
			http://www.springframework.org/schema/tx/spring-tx.xsd">
			
			<!-- 使用Spring整合c3p0的连接池,没有采用属性文件的方式 -->
			<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource ">
				<property name="driverClass" value="com.mysql.jdbc.Driver"/>
				<property name="jdbcUrl" value="jdbc:mysql:///spring_04"/>
				<property name="user" value="root"/>
				<property name="password" value="root"/>
			</bean>
			
			<!-- 配置平台事务管理器 -->
			<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
				<property name="dataSource" ref="dataSource"></property>
			</bean>
			<!-- 配置通知: 是Spring框架提供通知,不是咋们自己编写的 -->
			<tx:advice id="myAdvice" transaction-manager="transactionManager">
				<tx:attributes>
					<!-- 给具体的业务层的方法进行隔离级别,传播行为的具体的配置 -->
					<tx:method name="pay" isolation="DEFAULT" propagation="REQUIRED"/>
					<tx:method name="save*" isolation="DEFAULT"></tx:method>
					<tx:method name="find*" read-only="true"></tx:method>
				</tx:attributes>
			</tx:advice>
			<!-- 配置AOP的增强 -->
			<aop:config>
				<!-- Spring框架制作的通知,必须要使用该标签,如果是自定义的切面,使用aop:aspect标签 -->
				<aop:advisor advice-ref="myAdvice" pointcut="execution(public * com.baidu.*.*ServiceImpl.*(..))"></aop:advisor>
			</aop:config>
			
			<!-- 可以注入连接池 -->
			<bean id="accountDao" class="com.baidu.demo3.AccountDaoImpl">
				<property name="dataSource" ref="dataSource"></property>
			</bean>
			<!-- 管理service -->
			<bean id="accountService" class="com.baidu.demo3.AccountServiceImpl">
				<property name="accountDao" ref="accountDao"></property>
			</bean>
			
		</beans>
在dao层对代码进行了优化,优化了JdbcTemplate
	public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
		/*
	private JdbcTemplate jdbcTemplate;
	
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}*/
	//减钱
	@Override
	public void outMoney(String out, double money) {
		//jdbcTemplate.update("update username set money = money - ? where name = ?",money,out);
		this.getJdbcTemplate().update("update username set money = money - ? where name=?",money,out);
	}
	//加钱
	@Override
	public void inMoney(String in, double money) {
		//jdbcTemplate.update("update username set money = money + ? where name = ?",money,in);
		this.getJdbcTemplate().update("update username set money = money + ? where name=?",money,in);
	}

}

Xml和注解一起进行Spring的事务管理
		applicationContext4.xml
			<?xml version="1.0" encoding="UTF-8"?>
			<beans xmlns="http://www.springframework.org/schema/beans"
				xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
				xmlns:context="http://www.springframework.org/schema/context"
				xmlns:aop="http://www.springframework.org/schema/aop"
				xmlns:tx="http://www.springframework.org/schema/tx"
				xsi:schemaLocation="http://www.springframework.org/schema/beans 
				http://www.springframework.org/schema/beans/spring-beans.xsd
				http://www.springframework.org/schema/context
				http://www.springframework.org/schema/context/spring-context.xsd
				http://www.springframework.org/schema/aop
				http://www.springframework.org/schema/aop/spring-aop.xsd
				http://www.springframework.org/schema/tx 
				http://www.springframework.org/schema/tx/spring-tx.xsd">
				
				<!-- 开启注解的扫描 -->
				<context:component-scan base-package="com.baidu"/>
				<!-- 使用Spring整合c3p0的连接池,没有采用属性文件的方式 -->
				<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
					<property name="driverClass" value="com.mysql.jdbc.Driver"/>
					<property name="jdbcUrl" value="jdbc:mysql:///spring_04"/>
					<property name="user" value="root"/>
					<property name="password" value="root"/>
				</bean>
				
				<!-- 配置JdbcTemplate模板 -->
				<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
					<property name="dataSource" ref="dataSource"></property>
				</bean>
				<!-- 配置平台事务管理器 -->
				<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
					<property name="dataSource" ref="dataSource"></property>
				</bean>
				<!-- 开启事务注解 -->
				<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
				
			</beans>
Service层用注解 :
	//实现类
		@Service("accountService")
		@Transactional(isolation=Isolation.DEFAULT)
		public class AccountServiceImpl implements AccountService {
			@Resource(name="accountDao")
			private AccountDao accountDao;
		//	public void setAccountDao(AccountDao accountDao) {
		//		this.accountDao = accountDao;
		//	}
			//支付的方法
			@Override
			public void pay(String out, String in, double money) {
				//模拟两个操作
				//减钱
				accountDao.outMoney(out, money);
				//模拟异常
				//int i = 10/0;
				accountDao.inMoney(in, money);
			}
		}
使用纯注解的方式进行Spring事务管理 :
		/*
		 * 配置类,Spring声明式事务管理,纯注解的方式
		 * 
		 */
		@Configuration
		@ComponentScan(basePackages="com.baidu.demo5")
		@EnableTransactionManagement	//纯注解的方式,开启事务注解
		public class SpringConfig {
			@Bean(name="dataSource")
			public DataSource createDataSource() throws Exception{
				ComboPooledDataSource dataSource = new ComboPooledDataSource();
				dataSource.setDriverClass("com.mysql.jdbc.Driver");
				dataSource.setJdbcUrl("jdbc:mysql:///spring_04");
				dataSource.setUser("root");
				dataSource.setPassword("root");
				
				return dataSource;
			}
			
			//把dataSource注入进来
			@Bean(name="jdbcTemplate")
			@Resource(name="dataSource")
			public JdbcTemplate createJdbcTemplate(DataSource dataSource) {
				return new JdbcTemplate(dataSource);
			}
			
			//创建平台事务管理器对象
			@Bean(name="transactionManager")
			@Resource(name="dataSource")
			public PlatformTransactionManager createTransactionManager(DataSource dataSource) {
				return new DataSourceTransactionManager(dataSource);
			}
			
		}
1 : 传播行为 : 解决业务层方法之间互相调用的问题.
	传播行为的默认值 : 保证save和update方法在同一个事务中.

2 : Spring事务管理 : (1) : XML配置文件 ; (2) : XML+注解配置文件 ; (3) : 纯注解
	Spring框架提供了接口和实现类,进行事务管理的.
		PlatformTransactionManager接口 : 平台事务管理器,提供和回滚事务的.
			HibernateTransactionManager : hibernate框架事务管理的实现类.
			DataSourceTransactionManager : 使用JDBC或者MyBattis框架
		TransactionDefinition接口 : 事务的定义的信息.提供很多常量,分别表示隔离级别,传播行为.
			传播行为 : 事务的传播行为,解决service方法之间的调用的问题.
		
	Spring声明式事务管理,使用AOP技术进行事务管理.
		通知/增强 : 事务管理的方法,不用咋们自己编写.需要配置.
		
		连接池 DataSource ,存在Connection ,使用JDBC进行事务管理 ,conn.commit()
						|
						|注入
		平台事务管理器(必须配置的),是Spring提供接口,提交和回滚事务
						|
						|注入
		自己编写通知方法(事务管理),Spring提供通知,配置通知
						|
						|注入
				配置AOP增强 aop:config

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

推荐阅读

  • 远程办公经验为0,如何将日常工作平滑过度到线上?

    我是一名创业者,我的公司(深圳市友浩达科技有限公司)在2018年8月8日开始运营,现在还属于微型公司。这个春节假期,我一直十分关注疫情动向,也非常关心其对公司带来的影响。

    TVP官方团队
    TAPD 敏捷项目管理腾讯乐享企业邮箱企业编程算法
  • 数据中台,概念炒作还是另有奇效? | TVP思享

    作者简介:史凯,花名凯哥,腾讯云最具价值专家TVP,ThoughtWorks数据智能业务总经理。投身于企业数字化转型工作近20年。2000年初,在IBM 研发企业级中间件,接着加入埃森哲,为大型企业提供信息化架构规划,设计,ERP,云平台,数据仓库构建等技术咨询实施服务,随后在EMC负责企业应用转型业务,为企业提供云迁移,应用现代化服务。现在专注于企业智能化转型领域,是数据驱动的数字化转型的行业布道者,数据中台的推广者,精益数据创新体系的创始人,2019年荣获全球Data IQ 100人的数据赋能者称号,创业邦卓越生态聚合赋能官TOP 5。2019年度数字化转型专家奖。打造了行业第一个数据创新的数字化转型卡牌和工作坊。创建了精益数据创新方法论体系构建数据驱动的智能企业,并在多个企业验证成功,正在向国内外推广。

    TVP官方团队
    大数据数据分析企业
  • 扩展 Kubernetes 之 CRI

    使用 cri-containerd 的调用流程更为简洁, 省去了上面的调用流程的 1,2 两步

    王磊-AI基础
    Kubernetes
  • 扩展 Kubernetes 之 Kubectl Plugin

    kubectl 功能非常强大, 常见的命令使用方式可以参考 kubectl --help,或者这篇文章

    王磊-AI基础
    Kubernetes
  • 多种登录方式定量性能测试方案

    最近接到到一个测试任务,某服务提供了两种登录方式:1、账号密码登录;2、手机号+验证码登录。要对这两种登录按照一定的比例进行压测。

    八音弦
    测试服务 WeTest
  • 线程安全类在性能测试中应用

    首先验证接口参数签名是否正确,然后加锁去判断订单信息和状态,处理用户增添VIP时间事务,成功之后释放锁。锁是针对用户和订单的分布式锁,使用方案是用的redis。

    八音弦
    安全编程算法
  • 使用CDN(jsdelivr) 优化博客访问速度

    PS: 此篇文章适用于 使用 Github pages 或者 coding pages 的朋友,其他博客也类似.

    IFONLY@CUIT
    CDNGitGitHub开源
  • 扩展 Kubernetes 之 CNI

    Network Configuration 是 CNI 输入参数中最重要当部分, 可以存储在磁盘上

    王磊-AI基础
    Kubernetes
  • 聚焦【技术应变力】云加社区沙龙online重磅上线!

    云加社区结合特殊时期热点,挑选备受关注的音视频流量暴增、线下业务快速转线上、紧急上线防疫IoT应用等话题,邀请众多业界专家,为大家提供连续十一天的干货分享。从视野、预判、应对等多角度,帮助大家全面提升「技术应变力」!

    腾小云
  • 京东购物小程序购物车性能优化实践

    它是小程序开发工具内置的一个可视化监控工具,能够在 OS 级别上实时记录系统资源的使用情况。

    WecTeam
    渲染JavaScripthttps网络安全缓存

扫码关注云+社区

领取腾讯云代金券