Spring

  • IOC 控制反转
    把对象的创建、包括一些控制权交给 spring 容器管理。好处是整合各种框架,降低对象之间的耦合
    配置文件 *.xml
<bean id="唯一标识" class="对象类型" scope="singleton|prototype" init-method="初始化方法名字" destroy-method="销毁方法名字" lazy-init="true|false">
  • DI 依赖注入
    建立对象之间依赖关系的过程

setter 方法注入 <property name="属性名" ref="引用对象id">,要求对象为注入的属性提供一个 set 方法

构造方法注入 <constructor-arg index="构造方法的参数下标" ref="引用对象id">,要求对象为注入的属性提供一个构造方法

简化<bean autowire="byName|byType"> byName 根据属性名字,找到对象注入,byType 根据属性类型,找到对象注入

@Autowired 注解(属性上,setter方法上,构造方法上), 根据属性的类型,查找对象并进行注入
<context:annotation-config>

值注入 <property name="属性名" value="值">, <constructor-arg index="构造方法的参数下标" value="值">,@Value("${key}")

  • 通过 spring 容器管理连接池 Druid HikariCP

============================================================

1. 简化控制反转 (重点)

(spring 2.5开始), 提供了注解方式的控制反转和依赖注入

@Component 加在类上,spring 扫描到它之后,就把它交给 spring 容器管理

@Controller(表现层或叫控制层), @Service(业务逻辑层或叫服务层), @Repository(对应数据访问层), @Component(不属于前3层,不好分类时)

  • 控制单例多例子: @Scope(“singleton|prototype”)
  • 控制初始化和销毁方法:@PostConstruct 用来标记初始化方法, @PreDestroy 用来标记销毁方法
  • 控制懒惰初始化: @Lazy 加在类上,表示这个类在容器中是懒惰初始化的

注解方式的缺点在于,不能管理第三方的 class ,例如连接池等

2. 结合 mybatis (重点)

  1. 添加相关依赖
<!-- spring 依赖 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.22.RELEASE</version>
</dependency>

<!-- druid 连接池 依赖 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.13</version>
</dependency>

<!-- hikari 连接池 依赖 -->
<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>3.3.1</version>
</dependency>

<!-- mysql 数据库驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>

<!-- mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.6</version>
</dependency>

<!-- mybatis 与 spring 整合 -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.2</version>
</dependency>

<!-- 添加了 spring 对 jdbc 以及 transaction(tx) -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>4.3.22.RELEASE</version>
</dependency>
  1. 把 mybatis 中 sqlSessionFactory 交给 spring 管理
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!-- 把连接池对象,依赖注入给 SqlSessionFactoryBean 的dataSource 属性 -->
    <property name="dataSource" ref="dataSource"/>
</bean>
  1. 把 mybatis 中 的 接口mapper 交给 spring 容器管理
<!-- 一个接口,一个接口配置,比较麻烦 <bean id="heroDao" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="mapperInterface" value="com.westos.dao.HeroDao"/> <property name="sqlSessionFactory" ref="sqlSessionFactory"/> </bean>-->

<!-- 扫描 有哪些 mapper 接口需要交给 spring 管理 <bean id="heroDao"> <bean id="userDao"> -->
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.westos.dao"/>
</bean>
  1. 使用 mapper 接口
    可以直接用 context.getBean(mapper接口.class) 来获取

  2. 日志配置
    pom.xml中添加日志相关的依赖

<!-- 添加日志依赖 -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>1.7.2</version>
</dependency>

<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
    <scope>provided</scope>
</dependency>

提供 main/resources/logback.xml 配置文件

3. 声明式事务 (重点)

启用事务注解 让 @Transactional 注解生效

<tx:annotation-driven/>

jdbc中
connection.commit();
connection.rollback();

mybatis中
sqlSession.commit();
sqlSession.rollback();

选择事务管理器
事务管理器类,它来负责具体的事务管理操作(commit, rollback…)

  • DataSourceTransactionManager (对mybatis 来讲,选这个实现)
  • HibernateTransactionManager (对hibernate框架来讲)
<bean id="aaa" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

spring 中如果 @Transactional 的方法出现了 RuntimeException 或 Error , 事务回滚
@Transactional 的方法出现了 Exception 事务提交
如果希望遇到 Exception 也回滚事务 @Transational(rollbackFor=要回滚的异常类.class)

3.1 @Transactional的相关配置 (了解)

  • readOnly 只读事务 - 如果事务内没有增删改操作,只有查询操作,可以把事务设置为 readOnly=true,能提高一些性能
    如果在只读事务内执行增删改会报异常

  • timeout 事务的超时时间 2ms, 一旦事务运行超过了这个时间,就会结束事务,并回滚
    update where id=1 1ms
    update where id=2 1ms
    update where id=3 1ms
    rollback;
    超时时间的意义在于防止某个长时间运行的事务影响整个系统的性能,事务越短越好

  • isolation 隔离级别 (隔离级别越高,一致性越好,但性能越差)

    • 未提交读 - 脏读、不可重复读、幻读
    • 提交读 - 不可重复读、幻读 (oracle, sqlserver…)
    • 可重复读 - 幻读 (mysql默认)
    • 序列化读 - 没有上面的问题
  • propagation 传播行为

    • Propagation.REQUIRED 必须的,如果没有事务那么开始事务,如果有事务就加入 (默认的)
    • Propagation.SUPPORTS 支持的, 不会主动开始事务,但是会加入已经存在的事务
    • Propagation.REQUIRES_NEW 需要新的, 每次都会开始新事务
@Service
class ServiceA {
    @Transactional(propagation=Propagation.REQUIRES_NEW)  // tx1
    public void m1() {
        m2();
    }
}

@Service
class ServiceB {
    @Transactional(propagation=Propagation.REQUIRES_NEW) // tx2
    public void m2() { 

    }
}