前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SSH框架之Spring第四篇

SSH框架之Spring第四篇

作者头像
海仔
发布2019-09-23 15:28:20
4830
发布2019-09-23 15:28:20
举报
文章被收录于专栏:海仔技术驿站海仔技术驿站

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

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

代码语言:javascript
复制
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
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年09月22日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档