您现在的位置是:首页 >技术交流 >Spring(IOC,DI,事务)属性网站首页技术交流

Spring(IOC,DI,事务)属性

孤居自傲 2024-07-13 00:01:02
简介Spring(IOC,DI,事务)属性

Spring(IOC,DI,事务)属性

IOC

概念

Inverse Of Controll:控制反转;反转了依赖关系的满足方式,由之前的自己创建依赖对象,变为由工厂推送。(变主动为被动,即反转)解决了具有依赖关系的组件之间的强耦合,使得项目形态更加稳健

什么是IOC:

  • 控制反转,把对象创建和对象之间的调用过程,交给 Spring 进行管理
  • 使用 IOC 目的:为了耦合度降低
  • 入门案例就是 IOC 实现

IOC 底层原理:xml 解析、工厂模式、反射

项目中强耦合问题

public class UserDAOImpl implements UserDAO{....}
public class UserServiceImpl implements UserService {
    // !!!强耦合了UserDAOImpl!!!,使得UserServiceImpl变得不稳健!!
    private UserDAO userDAO= new UserDAOImpl();
    @Override
    public User queryUser() {
        return userDAO.queryUser();
    }
    ....
}

解决方案

// 不引用任何一个具体的组件(实现类),在需要其他组件的位置预留存取值入口(set/get)
public class UserServiceImpl implements UserService {
    // !!!不再耦合任何DAO实现!!!,消除不稳健因素!!
    private UserDAO userDAO;
    // 为userDAO定义set/get,允许userDAO属性接收spring赋值
    // Getters And Setters
    @Override
    public User queryUser() {
        return userDAO.queryUser();
    }
    ....
}
<!--userDao-->
<bean id="userDao" class="com.qf.hello.spring.dao.impl.UserDaoImpl"/>

<!--userService  ref:引用的其他bean的id-->
<bean id="userService" class="com.qf.hello.spring.service.impl.UserServiceImpl">
    <!-- property:设置属性name:对象的属性名ref:对象的属性值,因为userDao属性的对象类型所以属性ref -->
    <property name="userDao" ref="userDao"/>
</bean>

此时,如果需要更换其他UserDAO实现类,则UserServiceImpl不用任何改动!则此时的UserServiceImpl组件变得更加稳健

IOC 接口

  1. IOC 思想基于 IOC 容器完成,IOC 容器底层就是对象工厂
  2. Spring 提供 IOC 容器实现两种方式:(两个接口)
  • BeanFactory:IOC 容器基本实现,是 Spring 内部的使用接口,不提供开发人员进行使用

    • 加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象
  • ApplicationContext:BeanFactory 接口的子接口,提供更多更强大的功能,一般由开发人 员进行使用

    • 加载配置文件时候就会把在配置文件对象进行创建
      在这里插入图片描述
  1. IOC操作bean管理
    • Bean的管理指的是两个操作:1.Spring创建对象 2.Spring注入属性

    • Bean的常见的管理操作有两种方式:1.基于 xml 配置文件方式实现 2.基于注解方式实现

DI

概念

在Spring创建对象的同时,为其属性赋值,称之为依赖注入。

Set注入

创建对象时,Spring工厂会通过Set方法为对象的属性赋值。
代码演示:
定义目标Bean类型:

public class User {
    private Integer id;
    private String name;

    private String sex;
    private Integer age;
    private Date bornDate;
    private String[] hobbys;
    private Set<String> phones;
    private List<String> names;
    private Map<String,String> countries;
    private Properties files;
    //Getters And Setters
}

基本类型 + 字符串类型 + 日期类型:

<!-- 创建一个user对象,然后设置属性 -->
<bean id="user" class="com.qf.hello.spring.entity.User">
    <property name="id" value="1"/>
    <property name="name" value="魏凯"/>
    <property name="sex" value="男"/>
    <property name="age" value="23"/>
    <property name="bornDate" value="2000/03/05"/><!--注意格式"/"-->
</bean>

容器类型:

<!-- 创建一个user对象,然后设置属性 -->
<!-- 创建一个user对象,然后设置属性 -->
<bean id="user" class="com.qf.hello.spring.entity.User">
    <property name="id" value="1"/>
    <property name="name" value="魏凯"/>
    <property name="sex" value="男"/>
    <property name="age" value="23"/>
    <property name="bornDate" value="1999/10/15"/>
    <property name="hobbys">
        <array>
            <value>写代码</value>
            <value>JAVA中级开发工程师</value>
        </array>
    </property>

    <property name="phones">
        <set>
            <value>15112345678</value>
            <value>15114456668</value>
        </set>
    </property>

    <property name="names">
        <list>
            <value>张三</value>
            <value>赵六</value>
            <value>李四</value>
        </list>
    </property>

    <property name="countries">
        <map>
            <entry key="CN" value="中国"/>
            <entry key="USA" value="中国的某个省"/>
        </map>
    </property>

    <property name="files">
        <props>
            <prop key="driver">com.mysql.jdbc.Driver</prop>
            <prop key="url">jdbc:mysql:///</prop>
        </props>
    </property>

</bean>

自建类型:

<!--次要bean,被作为属性-->
<bean id="address" class="com.qf.hello.spring.entity.Address">
    <property name="province" value="湖北"/>
    <property name="city" value="武汉市"/>
</bean>

<!--主要bean,操作的主体-->
<bean id="user" class="com.qf.hello.spring.entity.User">
    <property name="address" ref="address" /><!--address属性引用addr对象-->
</bean>
<!--次要bean,被作为属性-->
<bean id="userDao" class="com.qf.hello.spring.dao.impl.UserDaoImpl" />

<!--主要bean,操作的主体-->
<bean id="userService" class="com.qf.hello.spring.service.impl.UserServiceImpl">
    <property name="userDao" ref="userDao" />
</bean>

构造注入【了解】

创建对象时,Spring工厂会通过构造方法为对象的属性赋值。

定义目标Bean类型:

public class Student {
    private Integer id;
    private String name;
    private String sex;
    private Integer age;
  
    //Constructors
  	public Student(Integer id , String name , String sex , Integer age){
      	this.id = id;
    	this.name = name;
  	    this.sex = sex;
	    this.age = age;
    }
}

注入:

<!--构造注入-->
<bean id="u3" class="com.qf.zcg.spring.day1.t2.ioc.Student">
    <constructor-arg name="id" value="1234" /> <!-- 除标签名称有变化,其他均和Set注入一致 -->
    <constructor-arg name="name" value="tom" />
    <constructor-arg name="age" value="20" />
    <constructor-arg name="sex" value="male" />
</bean>

自动注入

不用在配置中 指定为哪个属性赋值,及赋什么值
由spring自动根据某个 "原则" ,在工厂中查找一个bean,为属性注入属性值

public class UserServiceImpl implements UserService {
    private UserDAO userDAO;
    //Getters And Setters
    ....
}
<bean id="userDao" class="com.qf.spring.part1.injection.UserDaoImpl" />
<!--UserServiceImpl中的属性基于类型自动注入值 -->
<bean id="userService" class="com.qf.spring.part1.injection.UserServiceImpl" autowire="byType"></bean>
<bean id="userDao" class="com.qf.spring.part1.injection.UserDaoImpl" />
<!--UserServiceImpl中的属性基于类型自动注入值 -->
<bean id="userService" class="com.qf.spring.part1.injection.UserServiceImpl" autowire="byName"></bean>

事务

概念

名称描述
default(默认值)(采用数据库的默认的设置) (建议)
read-uncommited读未提交
read-commited读提交 (Oracle数据库默认的隔离级别)
repeatable-read可重复读 (MySQL数据库默认的隔离级别)
serialized-read序列化读

隔离级别由低到高为:read-uncommited < read-commited < repeatable-read < serialized-read

特性

  • 安全性:级别越高,多事务并发时,越安全。因为共享的数据越来越少,事务间彼此干扰减少。
  • 并发性:级别越高,多事务并发时,并发越差。因为共享的数据越来越少,事务间阻塞情况增多。

并发问题

事务并发时的安全问题

问题描述
脏读一个事务读取到另一个事务还未提交的数据。大于等于 read-commited 可防止
不可重复读一个事务内多次读取一行数据的相同内容,其结果不一致。大于等于 repeatable-read 可防止
幻影读一个事务内多次读取一张表中的相同内容,其结果不一致。serialized-read 可防止

传播行为

propagation 传播行为

当涉及到事务嵌套(Service调用Service)时,可以设置:

  • SUPPORTS = 不存在外部事务,则不开启新事务;存在外部事务,则合并到外部事务中。(适合查询)
  • REQUIRED = 不存在外部事务,则开启新事务;存在外部事务,则合并到外部事务中。 (默认值)(适合增删改)

读写性

readonly 读写性

  • true:只读,可提高查询效率。(适合查询)
  • false:可读可写。 (默认值)(适合增删改)

事务超时

timeout 事务超时时间

当前事务所需操作的数据被其他事务占用,则等待。

  • 100:自定义等待时间100(秒)。
  • -1:由数据库指定等待时间,默认值。(建议)

事务回滚

rollback-for 回滚属性

  • 如果事务中抛出 RuntimeException,则自动回滚
  • 如果事务中抛出 CheckException(非运行时异常 Exception),不会自动回滚,而是默认提交事务
  • 处理方案 : 将CheckException转换成RuntimException上抛,或 设置 rollback-for="Exception"

编织

将事务管理的Advice 切入需要事务的业务方法中

<aop:config>
	<aop:pointcut expression="execution(* com.qf.spring.service.UserServiceImpl.*(..))" id="pc"/>
    <!-- 组织切面 -->
    <aop:advisor advice-ref="txManager" pointcut-ref="pc"/>
</aop:config>

基于xml的步骤

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       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/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">
    
    <!--1. 配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--2. 配置 事务的通知-->
    <tx:advice id="txadvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="transferMoney" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!--3.织入切面-->
    <aop:config>
        <!--配置切点-->
        <aop:pointcut id="txpoint" expression="execution(* com.qf.service.impl.AccountServiceImpl.*(..))"/>
        <!--配置切面-->
        <aop:advisor advice-ref="txadvice" pointcut-ref="txpoint"></aop:advisor>
    </aop:config>
    
</beans>    
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。