java干货,spring声明式事务

一、编程式事务

1.1 什么是编程式事务

  • 编程式事务是指通过手动编写程序来管理事务,即通过编码的方式直接控制事务的提交回滚
  • 在java 中,通常使用事务管理器(如Spring 中的PlatformTransactionManager)来实现编程式事务

1.2 编程式事务的优缺点

  • 编程式事务的主要优点灵活性高,可以按照自己的需求来控制事务的粒度、模式等
  • 其缺点是需要编写大量的代码。可读性和可维护性不是很好,代码复用性不高

二、声明式事务

2.1 什么是声明式事务

  • 声明式事务是指使用 注解XML 配置的方式来控制事务的提交回滚,只要告诉哪个方法需要事务即可,这就是声明式,程序员只需要写配置即可

2.2 声明式事务的优点

  • 开发者只需配置即可,具体事务的控制实现由第三方框架实现,避免我们直接对事务进行操作
  • 声明式事务可以将业务代码事务逻辑分开来,提高代码的可读性和可维护性

2.3 Spring 事务管理器

  • Spring 声明式事务对应的依赖
    • spring-tx:包含声明式事务实现的基本规范(事务管理器规范接口事务增强等 )
    • spring-jdbc: 包含DataSource 方式事务管理器实现类(DataSource) DataSourceTransactionManager
    • spring-orm:包含其他持久层框架的事务管理器实现类 ,如Hibenate、jpa 等
    • 如果持久层使用的是JDBC、JdbcTemplate、MyBatis,那么就用DataSourceTransactionManager,也就是导入spring-jdbc依赖
    • 如果持久层使用的Hibenate,那么就用HibernateTransactionManager,也就是导入spring-orm 依赖

请添加图片描述

2.4 spring 声明式事务使用

  • 持久层框架使用JdbcTemplate、事务管理器使用DataSourceTransactionManager
  • 导入依赖
<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.25</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.8</version>
        </dependency>

        <!-- jdbcTemplate-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>6.0.6</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>6.0.6</version>
        </dependency>
  • jdbc.properties
datasource.url = jdbc:mysql://localhost:3306/数据库名称
datasource.driver = com.mysql.cj.jdbc.Driver
datasource.username = 账号
datasource.password = 密码
  • 编写配置类,JavaConfig.java
@Configuration
@ComponentScan(basePackages = {"com.binbin"})
@PropertySource("classpath:jdbc.properties")
//@EnableAspectJAutoProxy
@EnableTransactionManagement
public class JavaConfig {
    @Value("${datasource.driver}")
    private String driver;

    @Value("${datasource.url}")
    private String url;

    @Value("${datasource.username}")
    private String username;

    @Value("${datasource.password}")
    private String password;
    // 1 注入druid 连接池
    @Bean
    public DataSource dataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driver);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }

    // 2. 注入jdbcTemplate
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource){
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

    // 3. 事务管理 注入
    @Bean
    public TransactionManager transactionManager(DataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return  dataSourceTransactionManager;
    }
}
  • UserService
public interface UserService {
    public void updateById(Integer id,String name,Integer age) throws Exception;
}
  • UserServiceImpl
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    UserDao userDao;

    @Override
    @Transactional()
    public void updateById(Integer id,String name,Integer age) throws Exception {
        userDao.updateById(id, name, age);
    }
}
  • UserDao
@Repository
public class UserDao {
    @Autowired
    JdbcTemplate jdbcTemplate;

    public void updateById(Integer id,String name,Integer age) throws Exception {
        String sql = "update users set name = ?,age = ? where id = ?;";
        jdbcTemplate.update(sql,name,age,id);// 执行sql 语句
    }
}
  • 编写测试类
@SpringJUnitConfig(value = JavaConfig.class)
public class SpringTest {
    @Autowired
    UserService userService;
    @Test
    public void test() throws Exception {
        userService.updateById(1,"李四",20);
    }
}
  • 也可以直接在类上加@Transactional,方法上的会覆盖类上的注解
  • 只读模式设置,若执行非查询语句将会回滚
@Transactional(readOnly = true)
  • 事务超时设置:在指定时间内开启事务的方法未执行完会自动回滚
@Transactional(timeout = 5)
  • 指定触发回滚的异常,默认IO 异常 不触发
@Transactional(rollbackFor = Exception.class)
  • 指定异常不回滚
@Transactional(noRollbackFor = FileNotFoundException.class)
  • 指定四种隔离级别
  未提交读:@Transactional(isolation = Isolation.READ_UNCOMMITTED)
  已提交读:@Transactional(isolation = Isolation.READ_COMMITTED)
  可重复读:@Transactional(isolation = Isolation.REPEATABLE_READ)
  串行化:@Transactional(isolation = Isolation.SERIALIZABLE)

2.5 事务的传播行为

  • 什么是事务的传播行为?
    一个方法调用另一个方法时,如何处理当前事务上下文的问题。这些方法通常都有 @Transactional 注解。在 Spring 中,传播行为定义了被调用方法应该如何参与调用者的事务

  • 同一个类的方法互相调用,传播失效,因为传播需要通过代理对象,而同一个类的方法互相调用不走代理。因此只有不同类的方法调用,才会传播事务

  • 案例代码

@Service
public class TopServiceImpl implements TopService {

    @Autowired
    UserService userService;
    @Override
    @Transactional()
    public void topMethod(){
        userService.methodA();
        userService.methodB();
    }
}
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    UserDao userDao;

    @Override
    @Transactional(propagation = Propagation.xxx)
    public void methodA() {
        userDao.updateById(1,"王五",25);
    }

    @Override
    @Transactional(propagation = Propagation.xxx)
    public void methodB()  {
        userDao.updateById(1,"李六",35);
    }
}
  • propagation = Propagation.REQUIRED

    • 加了这个的方法一定会有事务
    • 如果调用方已经有事务,那么该方法就加入事务,如果没有,本方法就自己开启一个事务
    • 是默认的传播行为,适用于增删改查
  • propagation = Propagation.REQUIRES_NEW

    • 独立事务启动,同时挂起父方法的事务(暂停执行、提交事务)
      方法被调用时,无论当前是否存在一个活动的事务,它总是会启动一个新的、独立的事务。这个事务的回滚不会影响其他事务的回滚,其他事务的回滚也不会影响本事务的回滚
    • 调用方法和被调用方法不能在同一个类
    • 适用于内部事务和外部事务不存在关联的场景,如日志请添加图片描述
  • 24
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 数组是存储相同类型数据的集合,它们具有固定大小并且在创建后大小不可更改。在Java中,数组通过声明和初始化来创建。声明数组的语法形式如下: ```java int[] arr; // 声明了一个 int 类型的数组 ``` 在声明数组之后,需要通过初始化该数组,也就是为数组分配内存和赋初值。初始化数组的方式有两种:静态初始化和动态初始化。静态初始化是在声明数组的同时给数组元素赋初值的方法,语法形式如下: ```java int[] arr = {1, 2, 3, 4, 5}; // 静态初始化数组 ``` 动态初始化是在声明数组后通过循环或用户输入等方式给数组元素赋值的方法,语法形式如下: ```java int[] arr = new int[5]; // 动态初始化数组 for (int i = 0; i < arr.length; i++) { arr[i] = i + 1; } ``` Java 数组还具有一些常用的属性和方法,如`length`属性用来获取数组的长度,`clone()`方法用来复制数组,`toString()`方法用来将数组转换为字符串等。 除了一维数组外,Java 还支持多维数组,如二维数组、三维数组等。多维数组的声明和初始化方式与一维数组类似,只是需要使用多个`[]`来表示维度。 值得注意的是,Java 中的数组是引用类型,因此在传递数组参数时,实际上传递的是数组的引用,而不是数组的副本。这意味着在方法中对数组的修改会影响到原数组。 总的来说,了解和掌握 Java 数组的声明、初始化、属性和方法,并能灵活运用,对于 Java 编程是非常重要的。希望本文能够为大家提供关于 Java 数组的全面解析和干货知识。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值