欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

spring对数据库的操作、spring中事务管理的介绍与操作

程序员文章站 2022-07-05 10:19:57
jdbcTemplate的入门 创建maven工程 此处省略 导入依赖 配置文件中配置数据库连接池 测试 spring配置文件中数据库连接池的配置 C3P0数据库连接池的配置 依赖的jar包 xml配置 DBCP数据库连接池的配置 依赖的jar包 xml配置 Druid数据库连接池的配置 依赖的ja ......

jdbcTemplate的入门

  •   创建maven工程

 

     此处省略

 

  •   导入依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
  <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
  <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
      <!-- https://mvnrepository.com/artifact/org.springframework/spring-expression -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>  
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
<dependency>
    <groupId>aopalliance</groupId>
    <artifactId>aopalliance</artifactId>
    <version>1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.6.8</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>4.2.4.RELEASE</version>
</dependency>

   <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
        
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.38</version>
    </dependency>
   <!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>4.2.4.RELEASE</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.9</version>
    <scope>test</scope>
</dependency>

 

  •   配置文件中配置数据库连接池

      

<?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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
        
        <!-- 配置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://localhost:3306/spring"></property>
            <property name="username" value="root"></property>
            <property name="password" value="123"></property>
        </bean> -->
        
        <!-- jdbcTemplate的配置 -->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
</beans>

 

  •   测试
 1 @RunWith(SpringJUnit4ClassRunner.class)
 2 @ContextConfiguration("classpath:applicationContext.xml")
 3 public class JdbcTemplateTest {    
 4     @Autowired
 5     private JdbcTemplate jdbcTemplate;
 6     
 7     //增删改的测试
 8     @Test
 9     public void testName() throws Exception {
10         String sql = "insert into account values(null,?,?)";
11         jdbcTemplate.update(sql, "lisi",10000);
12     }
13 
14     //查询简单类型的测试
15     @Test
16     public void testName02() throws Exception {        
17         String sql = "select name from account where id=?";
18         String name = jdbcTemplate.queryForObject(sql, String.class,1);
19         System.out.println(name);
20     }
21     
22     //复杂类型的测试
23     @Test
24     public void testName03() throws Exception {
25         String sql = "select * from account where id=?";        
26         Account account = jdbcTemplate.queryForObject(sql, new MyRowMapper(),2);
27         System.out.println(account);        
28     }
29     
30     class MyRowMapper implements RowMapper<Account>{
31         @Override
32         public Account mapRow(ResultSet rs, int arg1) throws SQLException {
33             Account account = new Account();    //自己编写的实体类        
34             account.setId(rs.getInt("id"));        //id,name,money为实体类Account中的成员属性
35             account.setName(rs.getString("name"));
36             account.setMoney(rs.getDouble("money"));            
37             return account;
38         }        
39     }    
40 }

 

 

 



 

 

spring配置文件中数据库连接池的配置

 

  C3P0数据库连接池的配置

      依赖的jar包

    

<dependency>
    <groupId>c3p0</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.1.2</version>
</dependency>

 

      xml配置

        <!-- c3p0数据库连接池 -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
            <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring"></property>
            <property name="user" value="root"></property>
            <property name="password" value="123"></property>
        </bean> 

 

 

  DBCP数据库连接池的配置

      依赖的jar包

   

    <!-- dbcp数据库连接池 -->
    <dependency>
        <groupId>commons-dbcp</groupId>
        <artifactId>commons-dbcp</artifactId>
        <version>1.2.2</version>
    </dependency>
    <dependency>
        <groupId>commons-pool</groupId>
        <artifactId>commons-pool</artifactId>
        <version>1.5.3</version>
    </dependency>
    

 

 

      xml配置

 

     <!-- dbcp数据库连接池 -->
        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
            <property name="url" value="jdbc:mysql://localhost:3306/spring"></property>
            <property name="username" value="root"></property>
            <property name="password" value="123"></property>
        </bean> 

 

  Druid数据库连接池的配置

      依赖的jar包

      

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.0.18</version>
    </dependency>

 

      xml配置

 

      <!-- druid数据库连接池 -->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
            <property name="url" value="jdbc:mysql://localhost:3306/spring"></property>
            <property name="username" value="root"></property>
            <property name="password" value="123"></property>
        </bean>

 

  引入外部属性配置文件来配置数据库连接信息

 

     1. src/main/resources目录下创建jdbc.properties

jdbc.driverClass=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/spring

jdbc.username=root

jdbc.password=root

     2. spring 的核心配置文件中加载我们的jdbc.properties配置文件

 

<context:property-placeholder location="classpath:db.properties"/>

 


           3. 改写数据库连接池的配置,通过占位符来引用jdbc.properties属性文件中的内容

     <!-- druid数据库连接池 -->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value="${jdbc.driverClassName}"></property>
            <property name="url" value="${jdbc.url}"></property>
            <property name="username" value="${jdbc.username}"></property>
            <property name="password" value="${jdbc.password}"></property>
        </bean>

 

 



 

 

spring中事务的管理介绍

 

  事务的概念

事务主要是用来操作数据库的,他的使用是用来保证数据的完整性和一致性。

事务就是一系列的操作,它们被当做一个单独的工作单元。这些操作要么全部成功,要么全部失败。

  事务的特性(ACID)

原子性(atomicity): 事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成要么完全不起作用。

一致性(consistency): 一旦所有事务动作完成,事务就被提交。数据和资源就处于一种满足业务规则的一致性状态中。

隔离性(isolation): 可能有许多事务会同时处理相同的数据,因此每个事物都应该与其他事务隔离开来,防止数据损坏。

持久性(durability): 一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响。通常情况下,事务的结果被写到持久化存储器中。

 

  多个事务并发操作存在的问题

      读的问题

1、脏读:对于两个事务T1,T2, T1 读取了已经被 T2 更新但还没有被提交的字段。 之后, 若 T2 回滚,T1读取的内容就是临时且无效的。【读但未提交】

2、不可重复读:对于两个事务 T1, T2,T1 读取了一个字段,然后 T2 更新了该字段.。之后, T1再次读取同一个字段,值就不同了。【读更读】

3、幻读:对于两个事务 T1,T2, T1 从一个表中读取了一个字段,然后 T2 在该表中插入了一些新的行。之后,如果 T1 再次读取同一个表,就会多出几行。【读插读】

      写的问题

        丢失更新  :两个事务同时写一条记录,后一个事务把前一个事务的数据覆盖了,导致前一个事务的数据丢失。

 

  事务的隔离级别

      • 读未提交(read uncommited)

  允许事务读取其他事务未提交的更新,脏读 、不可重复读、幻读都会出现。

 

      • 读已提交(read commited)

  只允许事务读取其他事务已经提交的变更。可以避免脏读,但不可重复读和幻读问题仍然可能出现。

 

      • 可重复读(repeatable read)

  确保一个事务可以多次从一个字段中读取相同的值。在这个事务持续期间,禁止其他的事务对这个字段做更新操作。可以避免脏读、不可重复读,但是幻读仍然可能发生。

 

      • 串行化(serialzable)

  确保一个事务可以多次从一个表中读取相同的行。在这个事务持续期间,禁止其他事务对这张表进行插入、删除、更新操作。所有的并发都被避免,但是效率低下。

 

 

  spring的平台事务管理器

PlatformTransactionManager接口有一系列的实现类,用于不同的事务管理,其中最常用的类是【 HibernateTransactionManager】和【 DataSourceTransactionManager】。

HibernateTransactionManager用 Hibernate 框架存取数据库。

DataSourceTransactionManager通过 JDBC 操作数据库来管理事务。

它为事务管理封装了一组独立于技术的方法。无论使用 Spring 的哪种事务管理策略(编程式或声明式事务管理),事务管理器都是必须的

  spring中事务的定义

      •   事物的隔离级别
      •   事物的传播行为
      •   事物的超时信息
      •   事物是否只读

spring对数据库的操作、spring中事务管理的介绍与操作

 

 

  spring当中事务的状态信息定义

  •   状态是否有保存点
  •   事物是否完成
  •   是不是一个新的事物
  •   是否仅仅回滚

spring对数据库的操作、spring中事务管理的介绍与操作

 

 

spring当中的事务执行过程

 

Spring当中通过TransactionDefinition来对事物进行定义,然后通过PlatformTransactionManager来对事物进行操作,并且将操作后的事物状态,保存到TransactionStatus当中

 

spring对数据库的操作、spring中事务管理的介绍与操作

 

 

  spring当中事务的传播行为

 

    事务传播行为的介绍

事务方法的互相调用时(当一个事务方法被另一个事务方法调用时)必须指定事务应该如何传播。方法可能继续在现有事务中运行, 也可能开启一个新事务, 并在这个新的事务中运行。 事务的传播行为可以由传播属性指定。Propagation(传播,扩展)默认值是required,即是如果当前存在事务,则不进行创建,只是利用当前事务,如果当前没有事务,则是进行创建。

    举例说明:Required传播行为

spring对数据库的操作、spring中事务管理的介绍与操作

spring对数据库的操作、spring中事务管理的介绍与操作
    传播行为的取值

 

spring对数据库的操作、spring中事务管理的介绍与操作

 

 

 

 



 

 

Spring中事务的操作

 

Spring 既支持编程式事务管理,也支持声明式的事务管理。

  编程式事务管理

  声明式事务管理(xml配置方式和注解配置方式)

 

Spring中使用编程的方式进行事务管理

 

      spring配置文件中配置事务管理器和事务模版

     <!-- 配置事务的模版 -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
        <!-- 事务的模版 -->
        <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
            <property name="transactionManager" ref="transactionManager"></property>
        </bean>

 

      接口和实现类

1 public interface AccountDao {
2     void moneyOut(int from, double money);
3     void moneyIn(int in, double money);
4 }
 1 @Repository
 2 public class AccountDaoImpl implements AccountDao {    
 3     @Autowired
 4     private JdbcTemplate jdbcTemplate;
 5 
 6     @Override
 7     public void moneyOut(int from, double money) {
 8         String sql = "update account set money = money - ? where id = ?";
 9         jdbcTemplate.update(sql, money,from);
10     }
11 
12     @Override
13     public void moneyIn(int in, double money) {
14         String sql = "update account set money = money + ? where id = ?";
15         jdbcTemplate.update(sql, money,in);
16     }
17 }

 

 

1 public interface AccountService {
2     public void transferMoney(int from,int in,double money);
3 }
 1 @Service
 2 public class AccountServiceImpl implements AccountService{    
 3     @Autowired
 4     private AccountDao accountDao;
 5     
 6     //注入事务模版
 7     @Autowired
 8     private TransactionTemplate transactionTemplate;
 9 
10     @Override
11     public void transferMoney(int from, int in, double money) {
12                 //编程式事务代码
13         transactionTemplate.execute(new TransactionCallbackWithoutResult() {            
14             @Override
15             protected void doInTransactionWithoutResult(TransactionStatus arg0) {
16                 accountDao.moneyOut(from,money);                
17                 //抛出异常
18                 System.out.println(1/0);                
19                 accountDao.moneyIn(in,money);
20             }
21         });
22     }
23 }

 

      测试

 1 @RunWith(SpringJUnit4ClassRunner.class)
 2 @ContextConfiguration("classpath:applicationContext-tx.xml")
 3 public class TxTest {
 4     @Autowired
 5     private AccountService accountService;
 6     
 7     @Test
 8     public void testName() throws Exception {
 9         accountService.transferMoney(1, 2, 1000);
10     }
11 }

 

 

 

Spring中的声明式事务管理(基于xml配置)

 

      开启tx命名空间

spring对数据库的操作、spring中事务管理的介绍与操作

 

      配置声明式事务属性及切入点

   <!-- 声明事务管理:xml方式配置 -->
    <!-- 配置事务属性:传播行为,隔离级别,事务回滚,只读事务,超时结束 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!-- 指定事务方法的事务属性信息:如传播行为 -->
            <tx:method name="transfer*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    
    <!-- 配置事务切入点,以及把事务切入点和事务属性关联起来 -->
    <aop:config>
        <aop:pointcut expression="execution(* *.transfer*(..))" id="pointCut"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointCut"/>
    </aop:config>

 

      测试

 

 1 @RunWith(SpringJUnit4ClassRunner.class)
 2 @ContextConfiguration("classpath:applicationContext-tx-xml.xml")
 3 public class XmlTransactionTest {
 4     @Autowired
 5     private AccountService accountService;
 6     
 7     @Test
 8     public void testName() throws Exception {
 9         accountService.transferMoney(1, 2, 1000);
10     }
11 }

 

Spring中的声明式事务管理(基于注解的方式)

      开启tx命名空间

spring对数据库的操作、spring中事务管理的介绍与操作

 

      开启注解扫描

 

    <!-- 注解方式的声明式事务管理 -->
    <!-- 开启声明式事务管理的注解驱动 -->
    <tx:annotation-driven transaction-manager="transactionManager"/

 

      事务处理

      

@Service
@Transactional//注意加载service层,不要加在dao层
public class AccountServiceImpl implements AccountService{    
    @Autowired
    private AccountDao accountDao;
    
    @Override
    public void transferMoney(int from, int in, double money) {
        accountDao.moneyOut(from,money);        
        //抛出异常
        System.out.println(1/0);        
        accountDao.moneyIn(in,money);
    }
}

 

      测试

 1 @RunWith(SpringJUnit4ClassRunner.class)
 2 @ContextConfiguration("classpath:applicationContext-tx-annotation.xml")
 3 public class AnnotationTransactionTest {
 4     @Autowired
 5     private AccountService accountService;
 6     
 7     @Test
 8     public void testName() throws Exception {
 9         accountService.transferMoney(1, 2, 1000);
10     }
11 }

 

 

 

 Spring中的事务管理总结

  Spring 既支持编程式事务管理,也支持声明式的事务管理

  

  编程式事务管理: 将事务管理代码嵌入到业务方法中来控制事务的提交和回滚。在编程式管理事务时,必须在每个事务操作中包含额外的事务管理代码,这样的话,会引起业务代码混乱。

  

  声明式事务管理: 大多数情况下比编程式事务管理更好用。它将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。事务管理作为一种横切关注点, 可以通过 AOP 方法模块化。Spring 通过 Spring AOP 框架支持声明式事务管理。建议使用这种方式。

  

    注意基于注解的声明式事务管理,注解不要写在dao层处理,应该将事务的处理提取到service层,因为事务的回滚一般会牵涉到多个dao的使用,所以在service层处理,能够最大化的保证数据的完整性。