Spring 入门(2):JdbcTemplate 与 spring中的事务

4 篇文章 1 订阅

概念及准备

Spring 框架对 JDBC 进行封装,使用 JdbcTemplate 方便实现对数据库操作

  • 该模本所需要的 jar 包如下所示:
    在这里插入图片描述

  • 在spring配置文件配置数据库连接池

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
     destroy-method="close">
     <property name="url" value="jdbc:mysql:///test" />
     <property name="username" value="root" />
     <property name="password" value="root" />
     <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    </bean>
    
  • 配置JdbcTemplate对象,注入 DataSource

    <!-- JdbcTemplate 对象 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
     <!--注入 dataSource-->
     <property name="dataSource" ref="dataSource"></property><!--set方式注入-->
    </bean>	
    
  • 创建service类,创建dao类,在dao注入jdbcTemplate对象

    • 配置文件,打开注解的扫描
        <!-- 组件扫描 -->
       <context:component-scan base-package="com.atguigu"></context:component-scan>
      
    • Service类和Dao 类 的编写
      @Service
      public class BookService {
       //注入 dao
       @Autowired
       private BookDao bookDao;
      }
      
      @Repository
      public class BookDaoImpl implements BookDao {
       //注入 JdbcTemplate
       @Autowired
       private JdbcTemplate jdbcTemplate;
      }
      

JdbcTemplate 操作数据库(添加操作)

对应数据库创建实体类

在这里插入图片描述

编写 service 和 dao

在dao进行数据库添加操作时需要调用 JdbcTemplate 对象里面 update方法 实现添加操作
在这里插入图片描述
一共两个参数:
⚫ 第一个参数:sql语句
⚫ 第二个参数:可变参数,设置sql语句值

@Repository
public class BookDaoImpl implements BookDao {
	 //注入 JdbcTemplate
	 @Autowired
	 private JdbcTemplate jdbcTemplate;
	 //添加的方法
	 @Override
	 public void add(Book book) {
		 //1 创建 sql 语句
		 String sql = "insert into t_book values(?,?,?)";
		 //2 调用方法实现
		 Object[] args = {book.getUserId(), book.getUsername(),book.getUstatus()};
		 int update = jdbcTemplate.update(sql,args);
		 System.out.println(update);
	 }
}

测试结果如下:
在这里插入图片描述

JdbcTemplate 操作数据库(修改和删除操作)

  • 修改操作:
    @Override
    public void updateBook(Book book) {
     String sql = "update t_book set username=?,ustatus=? where user_id=?";
     Object[] args = {book.getUsername(), book.getUstatus(),book.getUserId()};
     int update = jdbcTemplate.update(sql, args);
     System.out.println(update);
    }
    
  • 删除操作:
    //2、删除
    @Override
    public void delete(String id) {
     String sql = "delete from t_book where user_id=?";
     int update = jdbcTemplate.update(sql, id);
     System.out.println(update);
    }
    
  • 使用JdbcTemplate 模板所实现的 “增删改” 都是调用了同一个 “update” 方法

JdbcTemplate 操作数据库(查询返回某个值)

//查询表记录数
@Override
public int selectCount() {
 String sql = "select count(*) from t_book";
//queryForObject方法中:第一个参数代表--sql语句;第二个参数代表--返回类型class  
 Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
 return count;
}

JdbcTemplate 操作数据库(查询返回对象)

//查询返回对象
@Override
public Book findBookInfo(String id) {
	 String sql = "select * from t_book where user_id=?";
	 //调用方法
	/*
		queryForObject方法中:
			第一个参数:sql语句
			第二个参数:RowMapper 是接口,针对返回不同类型数据,使用这个接口里面 实现类 完成数据封装
			第三个参数:sql 语句值
	*/
	 Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book>(Book.class), id);
	 return book;
}

JdbcTemplate 操作数据库(查询返回集合)

//查询返回对象
@Override
public Book findBookInfo(String id) {
 String sql = "select * from t_book where user_id=?";
 //调用方法
/*
	queryForObject方法中:
		第一个参数:sql语句
		第二个参数:RowMapper 是接口,针对返回不同类型数据,使用这个接口里面 实现类 完成数据封装
		第三个参数:sql 语句值
*/
 Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book>(Book.class), id);
 return book;
}

JdbcTemplate 操作数据库(批量操作)

批量操作:操作表里面多条记录

  • JdbcTemplate 实现批量添加操作
    在这里插入图片描述
  • ⚫ 有两个参数
    ⚫ 第一个参数:sql语句
    ⚫ 第二个参数:List集合,添加多条记录数据

批量添加操作

代码如下:

//批量添加
@Override
public void batchAddBook(List<Object[]> batchArgs) {
 String sql = "insert into t_book values(?,?,?)";
//batchUpdate方法 第一个参数:sql语句		第二个参数:List集合,添加多条记录数据
 int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
 System.out.println(Arrays.toString(ints));
}

测试代码如下:

//批量添加测试
List<Object[]> batchArgs = new ArrayList<>();
Object[] o1 = {"3","java","a"};
Object[] o2 = {"4","c++","b"};
Object[] o3 = {"5","MySQL","c"};
batchArgs.add(o1);
batchArgs.add(o2);
batchArgs.add(o3);
//调用批量添加
bookService.batchAdd(batchArgs);

批量修改操作

//批量修改 
@Override public void batchUpdateBook(List<Object[]> batchArgs) {
	String sql = "update t_book set username=?,ustatus=? where user_id=?";
	int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
	System.out.println(Arrays.toString(ints
	} 
	
//批量修改测试代码
List<Object[]> batchArgs = new ArrayList<>(); 
Object[] o1 = {"java0909","a3","3"}; 
Object[] o2 = {"c++1010","b4","4"}; 
Object[] o3 = {"MySQL1111","c5","5"}; 
batchArgs.add(o1); 
batchArgs.add(o2); 
batchArgs.add(o3); 
//调用方法实现批量修改 
bookService.batchUpdate(batchArgs);

批量删除操作

//批量删除 
@Override public void batchDeleteBook(List<Object[]> batchArgs) {
	String sql = "delete from t_book where user_id=?";
	int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
	System.out.println(Arrays.toString(ints));
	} 
//批量删除 测试
List<Object[]> batchArgs = new ArrayList<>();
Object[] o1 = {"3"}; 
Object[] o2 = {"4"}; 
batchArgs.add(o1); 
batchArgs.add(o2); 
//调用方法实现批量删除 
bookService.batchDelete(batchArgs);

事务操作的提出场景

事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败,所有操作都失败。

典型场景:银行转账(下面操作就为一个事务操作)

  • lucy 转账100元 给mary
  • lucy少100,mary多100

因此事务存在四个特性(ACID)

  • 原子性
  • 一致性
  • 隔离性
  • 持久性

转账场景模拟:事务提出的场景

  • 对数据库的操作应该交给 dao层,即增加账户的余额或者减少账户余额
  • 对这些方法的整合利用应当交给 service层,如下
    在这里插入图片描述
  1. 创建数据库表,添加记录
    在这里插入图片描述

  2. 创建 service,搭建 dao,完成对象创建和注入关系
    在 service 中注入dao,在 dao 中注入 JdbcTemplate,在 JdbcTemplate 中注入 DataSource

    @Service 
    public class UserService {
    	//注入dao
    	@Autowired private UserDao userDao;
    } 
    @Repository
    public class UserDaoImpl implements UserDao {
    	@Autowired
    	private JdbcTemplate jdbcTemplate; 
    }
    
  3. 在dao创建两个方法:增加钱和减少钱的方法,

    @Repository 
    public class UserDaoImpl implements UserDao {
    	@Autowired 
    	private JdbcTemplate jdbcTemplate; 
    	//lucy转账100给mary 
    	//少钱 
    	@Override 
    	public void reduceMoney() {
    		String sql = "update t_account set money=money-? where username=?";
    		jdbcTemplate.update(sql,100,"lucy");
    	}
    	//多钱 
    	@Override 
    	public void addMoney() {
    		String sql = "update t_account set money=money+? where username=?";
    		jdbcTemplate.update(sql,100,"mary");
    	} 
    }
    
  4. 在service创建整合的方法(转账的方法)

    @Service 
    public class UserService {
    	//注入dao
    	@Autowired
    	private UserDao userDao;
    	//转账的方法
    	public void accountMoney() {
    		//lucy少100
    		userDao.reduceMoney();
    		//mary多100
    		userDao.addMoney();
    	}
    }
    

上面代码,如果正常执行没有问题的,但是如果代码执行过程中出现异常,有问题
在这里插入图片描述
上满问题解决的方式:利用事务进行解决

在这里插入图片描述

Spring 事务管理介绍

1、事务添加到 JavaEE 三层结构里面 Service层(业务逻辑层)
2、在Spring进行事务管理操作
(1)有两种方式 :编程式事务管理声明式事务管理(使用)
3、声明式事务管理
(1)基于注解方式(使用)
(2)基于xml配置文件方式
4、在Spring进行声明式事务管理,底层使用AOP原理

Spring事务管理API提供了一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类
在这里插入图片描述

注解声明式事务管理器

环境配置

  1. 在spring配置文件中配置事务管理器

    <!--创建事务管理器--> 
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
    	<!--注入数据源-->
    	<property name="dataSource" ref="dataSource"></property>
    </bean>
    
  2. 在 Spring 配置文件中开启事务注解
    在spring配置文件引入名称空间 xmlns:tx="http://www.springframework.org/schema/tx"

    <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">
    

    开启事务注解:

    <!--开启事务注解--> 
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
    
  3. service类上面(或者service类里面方法上面)添加 事务注解:
    @Transactional,这个注解添加到类上面,也可以添加方法上面

    • 如果把这个注解添加类上面,这个类里面所有的方法都添加事务
    • 如果把这个注解添加方法上面,为这个方法添加事务
    @Service 
    @Transactional 
    public class UserService {}
    

参数配置

service类 上面添加注解 @Transactional ,在这个注解里面可以配置事务的相关参数
在这里插入图片描述
propagation:事务传播行为

propagation 主要为那些事务中套事务的场景(即事务的传播行为)指定运行策略,有7种可选策略,如下所示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

ioslation:事务隔离级别

由于事务存在隔离性,因此很容易产生三种可能出现的读问题:脏读、不可重复读、虚(幻)读。

  • 脏读:一个未提交事务读取到另一个未提交事务的数据
    在这里插入图片描述
  • 不可重复读:一个未提交事务读取到另一提交事务修改数据
  • 虚读: 一个未提交事务读取到另一提交事务添加数据

上面这三种隔离问题的解决防范为:设置事务的隔离级别,解决读问题
在这里插入图片描述
在这里插入图片描述

timeout:超时时间

  • (1)事务需要在一定时间内进行提交,如果不提交则进行回滚
  • (2)默认值是 -1 ,设置时间以秒单位进行计算

readOnly:是否只读

读:查询操作,写:添加修改删除操作

  • (2)readOnly默认值false,表示可以查询,可以添加修改删除操作
  • (3)设置readOnly值是true,设置成true之后,只能查询

rollbackFor:回滚
(1)设置出现哪些异常进行事务回滚

noRollbackFor:不回滚
(1)设置出现哪些异常不进行事务回滚

xml 声明式事务管理

在 spring 配置文件中进行配置

  • 第一步 配置事务管理器
  • 第二步 配置通知
  • 第三步 配置切入点和切面

配置文件如下:

<!--1 创建事务管理器--> 
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
	<!--注入数据源--> 
	<property name="dataSource" ref="dataSource"></property> 
</bean> 
<!--2 配置通知--> 
<tx:advice id="txadvice">
	<!--配置事务参数--> 
	<tx:attributes>
		<!--指定哪种规则的方法上面添加事务-->
		<tx:method name="accountMoney" propagation="REQUIRED"/>
		<!--<tx:method name="account*"/>--> 
	</tx:attributes>
 </tx:advice>
<!--3 配置切入点和切面--> 
<aop:config> 
	<!--配置切入点--> 
	<aop:pointcut id="pt" expression="execution(* com.atguigu.spring5.service.UserService.*(..))"/> 
	<!--配置切面--> 
	<aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
</aop:config>

完全注解声明式管理

  • 创建配置类,使用配置类替代 xml配置文件
@Configuration 
//配置类 
@ComponentScan(basePackages = "com.atguigu") 
//组件扫描 
@EnableTransactionManagement 
//开启事务 
public class TxConfig {
	//创建数据库连接池
	@Bean
	public DruidDataSource getDruidDataSource() {
		DruidDataSource dataSource = new DruidDataSource();
		dataSource.setDriverClassName("com.mysql.jdbc.Driver");
		dataSource.setUrl("jdbc:mysql:///user_db");
		dataSource.setUsername("root");
		dataSource.setPassword("root");
		return dataSource;
	}
	//创建JdbcTemplate对象
	@Bean
	public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
		//到ioc容器中根据类型找到dataSource
		JdbcTemplate jdbcTemplate = new JdbcTemplate();
		//注入dataSource
		jdbcTemplate.setDataSource(dataSource);
		return jdbcTemplate;
	} 
	//创建事务管理器 
	@Bean
	public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) {
		DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
		transactionManager.setDataSource(dataSource); 
		return transactionManager;
	}
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值