spring学习之Data Access

一图千言之spring模块组成

Transaction Management

全面的事务支持。Spring Framework 为事务管理提供了一致的抽象,具有以下优点

  • 跨不同事务 API 的一致编程模型,例如 Java 事务 API (JTA)、JDBC、Hibernate 和 Java Persistence API (JPA)。

  • 支持声明式事务管理

  • 比复杂的事务 API(例如 JTA)更简单的用于程序化事务管理的 API。

  • 与 Spring 的数据访问抽象的完美集成

理解 Spring 框架事务抽象

public interface PlatformTransactionManager extends TransactionManager {

    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;

    void commit(TransactionStatus status) throws TransactionException;

    void rollback(TransactionStatus status) throws TransactionException;
}

这主要是一个服务提供者接口 (SPI)。按照 Spring 的理念,TransactionException可以由任何PlatformTransactionManager接口的方法抛出的 是未经检查的(即,它扩展了java.lang.RuntimeException类)。

TransactionManager实现通常需要了解它们工作的环境:JDBC、JTA、Hibernate 等等。以下示例展示了如何定义本地PlatformTransactionManager实现(在本例中,使用普通 JDBC。)

例子

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${jdbc.driverClassName}" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
</bean>


<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

Declarative Transaction Management 

声明式事务对应用程序代码的影响最小,因此最符合非侵入式轻量级容器的理想。Spring框架的声明性事务支持是通过AOP代理启用的,而事务通知是由元数据驱动的(目前是基于XML或基于注释的)。AOP与事务性元数据的结合产生了一个AOP代理,该代理使用TransactionInterceptor和适当的TransactionManager实现来驱动围绕方法调用的事务。

拦截器通过检查方法返回类型来检测所需的事务管理风格。返回响应式类型(如Publisher或Kotlin Flow(或这些类型的子类型)的方法符合响应式事务管理。所有其他返回类型(包括void)都使用强制事务管理的代码路径。

Rolling Back a Declarative Transaction

当抛出的异常是RuntimeException的实例或子类时。(默认情况下,error实例也会导致回滚)。从事务方法抛出的检查异常不会导致默认配置中的回滚。

Using @Transactional

对于声明性事务,事务名称总是完全限定类名+事务通知类的方法名例如,如果BusinessService类的handlePayment(..)方法启动了一个事务,则事务的名称将为com.example.BusinessService.handlePayment

注意事项:事务有可能失效的场景

  • 应该只对具public的方法应用@Transactional注释。如果使用@Transactional注释protectedprivate, or package-visible 的方法,不会引发错误,但注释的方法不会显示配置的事务设置。可以通过下面这样设置对非pubilc的方法设置事务。
/**
 * Register a custom AnnotationTransactionAttributeSource with the
 * publicMethodsOnly flag set to false to enable support for
 * protected and package-private @Transactional methods in
 * class-based proxies.
 *
 * @see ProxyTransactionManagementConfiguration#transactionAttributeSource()
 */
@Bean
TransactionAttributeSource transactionAttributeSource() {
    return new AnnotationTransactionAttributeSource(false);
}
  • 在代理模式(这是默认的)中,只有通过代理进入的外部方法调用被拦截。这意味着自调用(实际上,目标对象中的一个方法调用目标对象的另一个方法)不会在运行时导致实际事务,即使被调用的方法被标记为@Transactional。
  • @EnableTransactionManagement和<tx:注释驱动/>只在定义它们的同一个应用程序上下文中的bean上寻找@Transactional。这意味着,如果您将注释驱动的配置放在一个DispatcherServlet的WebApplicationContext中,它只会在controllers中检查@Transactional bean,而不是在services中

@Transactional Settings

默认@Transactional设置如下:

propagation设置为PROPAGATION_REQUIRED。

isolation级别为ISOLATION_DEFAULT。

事务是读写的。

事务超时默认为基础事务系统的默认超时,如果不支持超时,则为none。

任何RuntimeException都会触发回滚,而任何checked Exception不会

DAO Support

Spring中的数据访问对象(DAO)支持旨在以一致的方式简化数据访问技术(如JDBC、Hibernate或JPA)。这使您可以非常容易地在上述持久性技术之间进行切换,而且还使您不必担心捕获特定于每种技术的异常。

确保数据访问对象(dao)或repositories提供异常转换的最佳方法是使用@Repository注释。该注释还允许组件扫描支持查找和配置dao和repositories

Data Access with JDBC

Spring框架的JDBC抽象框架由四个不同的包组成

  • core: org.springframework.jdbc.core包包含了JdbcTemplate类和它的各种回调接口,以及各种相关类
  • datasource: org.springframework.jdbc.datasource包包含了一个实用程序类
  • 数据源访问和各种可以用于测试的简单数据源实现以及在Java EE容器外运行未修改的JDBC代码
  • object: org.springframework.jdbc.object包包含代表RDBMS的类查询、更新和存储过程作为线程安全的、可重用的对象
  • support: org.springframework.jdbc.support包提供了SQLException转换功能和一些实用程序类

Using JdbcTemplate

JdbcTemplate类:实例是线程安全的
•运行SQL查询
•更新语句和存储过程调用
•对ResultSet实例进行迭代,并提取返回的参数值。
•捕获JDBC异常并将其转换为通用的、信息更丰富的异常

private final RowMapper<Actor> actorRowMapper = (resultSet, rowNum) -> {
  Actor actor = new Actor();
  actor.setFirstName(resultSet.getString("first_name"));
  actor.setLastName(resultSet.getString("last_name"));
  return actor;
};
public List<Actor> findAllActors() {
  return this.jdbcTemplate.query( "select first_name, last_name from t_actor",
actorRowMapper);
}

JDBC Batch Operations

  • JdbcTemplate
public class JdbcActorDao implements ActorDao {
        private JdbcTemplate jdbcTemplate;
        public void setDataSource(DataSource dataSource) {
            this.jdbcTemplate = new JdbcTemplate(dataSource);
        }
        public int[] batchUpdate(final List<Actor> actors) {
            return this.jdbcTemplate.batchUpdate(
                    "update t_actor set first_name = ?, last_name = ? where id = ?",
                    new BatchPreparedStatementSetter() {
                        public void setValues(PreparedStatement ps, int i) throws
                                SQLException {
                            Actor actor = actors.get(i);
                            ps.setString(1, actor.getFirstName());
                            ps.setString(2, actor.getLastName());
                            ps.setLong(3, actor.getId().longValue());
                        }
                        public int getBatchSize() {
                            return actors.size();
                        }
                    });
        }
        // ... additional methods
    }
  • Batch Operations with Multiple Batches 多批次批处理 
public class JdbcActorDao implements ActorDao {

    private JdbcTemplate jdbcTemplate;

    public void setDataSource(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    public int[][] batchUpdate(final Collection<Actor> actors) {
        int[][] updateCounts = jdbcTemplate.batchUpdate(
                "update t_actor set first_name = ?, last_name = ? where id = ?",
                actors,
                100,
                (PreparedStatement ps, Actor actor) -> {
                    ps.setString(1, actor.getFirstName());
                    ps.setString(2, actor.getLastName());
                    ps.setLong(3, actor.getId().longValue());
                });
        return updateCounts;
    }

    // ... additional methods
}

此调用的批处理更新方法返回一个数组int数组,其中包含每个批处理的数组条目,以及每个更新受影响的行数的数组。顶级数组的长度表示运行的批次数,第二级数组的长度表示该批次中的更新次数。每个批次中的更新数量应该是为所有批次提供的批次大小(除了最后一个可能更少),具体取决于提供的更新对象的总数。每个更新语句的更新计数是 JDBC 驱动程序报告的计数。如果计数不可用,则 JDBC 驱动程序返回值-2

Simplifying JDBC Operations with the SimpleJdbc Classes

https://docs.spring.io/spring-framework/docs/5.3.9/reference/html/data-access.html#jdbc-simple-jdbc

提供了一个简化的配置可以通过JDBC驱动程序检索数据库元数据的优点 

参数和数据值处理的常见问题

响应式关系数据库处理R2DBC

Reactive Relational Database Connectivity。R2DBC是基于Reactive Streams标准来设计的。通过使用R2DBC,你可以使用reactive API来操作数据。

Object Relational Mapping (ORM) Data Access

Hibernate

从 Spring Framework 5.3 开始,Spring 需要 Hibernate ORM 5.2+ 才能用于 Spring

  • SessionFactory Setup in a Spring Container
  • Three Options for JPA Setup in a Spring Environment

Marshalling XML by Using ObjectXML Mappers

Object-XML映射(O-X映射是在XML文档和对象之间进行转换的行为。这个转换过程也称为XML编组或XML序列化)。

  • Ease of configuration

             Spring 的 bean factory 可以轻松配置 marshallers

  • Consistent Interfaces 

           Spring 的 OX 映射通过两个全局接口运行:Marshaller和 Unmarshaller

  • Consistent Exception Hierarchy

          Spring 提供了从底层 OX 映射工具的异常到它自己的异常层次结构的转换,以XmlMappingException为根            异常

Marshaller将object序列化为 XML,Unmarshaller将 XML 流反序列化为object

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值