一,Spring中Bean的自动装配
Spring提供的4种自动装配类型
属性 | 说明 |
no | 不使用自动装配。Bean的依赖关系必须通过property元素定义 |
byType | 根据属性类型自动装配 |
byName | 根据属性名自动装配 |
constructor | 与byType的方式类似,不同之处在它应用于构造器参数 |
1.byName自动装配
解释:UserService中的userDao属性名与UserDao bean的id相同("userDao"),所以可以匹配自动注入。
@Component
public class UserService {
@Autowired
private UserDao userDao;
public void insert() {
userDao.insert();
}
}
@Component("userDao")
public class UserDao {
public void insert() {
System.out.println("Insert by Dao");
}
}
2.byType自动装配
解释:UserService中的userDao属性类型与UserDaoImpl bean的class类型相同(都实现了UserDao接口),所以可以匹配自动注入。
@Component
public class UserService {
@Autowired
private UserDao userDao;
public void insert() {
userDao.insert();
}
}
@Component
public class UserDaoImpl implements UserDao {
public void insert() {
System.out.println("Insert by Dao");
}
}
3.constructor自动装配
解释:构造函数参数类型与UserDao bean class类型匹配,Spring会自动注入到构造函数中。
@Component
public class UserService {
private final UserDao userDao;
@Autowired
public UserService(UserDao userDao) {
this.userDao = userDao;
}
public void insert() {
userDao.insert();
}
}
4.autowire自动装配
解释:autowire是byName和byType的结合,既可以根据属性名匹配也可以根据属性类型匹配自动注入。
@Service
public class UserService {
@Autowired
private UserDao userDao;
public void insert() {
userDao.insert();
}
}
二,Spring中Bean的作用域
作用域 | 说明 |
singleton | 默认值。以单例模式创建Bean的实例,即容器中该Bean的实例只会被创建一个 |
prototype | 每次从容器中获取Bean时,都会创建一个新的实例 |
request | 用于Web应用环境,针对每次HTTP请求都会创建一个实例 |
session | 用于Web应用环境,同一个会话共享同一个实例 |
global session | 仅在Portlet的Web应用中使用,同一个全局会话共享一个实例。对于非Portlet环境,等同于session |
<!--配置DAO-->
<bean id="sysUserMapper" class="cn.cvs.dao.SysUserMapperImpl" autowire="byType" scope="singleton" />
使用@Scope注解指定Bean的作用域
@Scope("prototype")
@Service
public class SysUserServiceImpl implements SysUserService {
// 业务编码略
}
三,Spring 声明式事务
Spring 的事务管理分为两种:
- 编程式事务管理:通过编写代码实现的事务管理,包括定义事务的开始、正常执行后的事务提交和异常时的事务回滚。
- 声明式事务管理:建立在 AOP 之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
声明式事务管理不需要入侵代码,并且提供了 @Transactional 注解更为简单、快捷地进行事务操作,推荐使用。
事务属性介绍
事务隔离级别(Isolation)
事务隔离级别指的是若干个并发的事务之间的隔离程度,一般可分为以下五个级别:
- DEFAULT:默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这个值就是READ_COMMITTED。
- READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。
- READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
- REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。
- SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
1.spring的配置文件:
<?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"
xmlns:aop="http://www.springframework.org/schema/aop"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--1.配置数据源-->
<context:property-placeholder location="database.properties"></context:property-placeholder>
<!--2.配置环境 配置数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driver}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--配置 SqlSessionFactoryBean-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
</bean>
<!--配置 MapperScannerConfigurer-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.example.mapper"></property>
</bean>
<!-- 配置事务管理器,使用 Spring 的事务管理 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:advice id="advice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 事务配置
属性:name:对哪些方法起作用,例如:insert* 表示所有以 insert 开头的方法名称。
一般只需要对增、删、改方法添加事务
rollback-for:指定需要进行事务回滚的异常类,默认是 uncheck 异常
其它属性一般默认即可
-->
<tx:method name="insert*" rollback-for="java.lang.Exception"/>
<tx:method name="delete*" rollback-for="java.lang.Exception"/>
<tx:method name="update*" rollback-for="java.lang.Exception"/>
</tx:attributes>
</tx:advice>
<aop:aspectj-autoproxy proxy-target-class="true" />
<!-- 编写 aop,对目标生成代理,进行事务的通知 -->
<aop:config>
<!-- 配置切点表达式 -->
<aop:pointcut id="txPointcut" expression="execution (* com.example.service.*ServiceImpl.*(..))"/>
<!-- 将切点和事务的通知整合 -->
<aop:advisor advice-ref="advice" pointcut-ref="txPointcut"/>
</aop:config>
<!--开启注解事务-->
<tx:annotation-driven transaction-manager="transactionManager"/>
<context:component-scan base-package="com.example.service"/>
</beans>
2. 需要使用的依赖:
<dependencies>
<!-- spring 依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<!-- mybatis 依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.8</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<!-- mysql 依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<!-- util-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.8</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.20.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.20.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.19</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.9.5</version>
</dependency>
</dependencies>
数据库隔离级别问题中的三种现象:
- 脏读(Dirty Read)
指一个事务读取了另一个事务还没有提交的数据。如果该事务之后回滚,读取的数据就变成了无效的数据。
例如:事务1更新了一条记录但还没有提交,事务2读取到了事务1更新后的记录。如果事务1后回滚,事务2读取到的就是无效的数据。
- 幻读(Phantom Read)
指在一个事务内读取数据库两次,两次读取结果集不同,但是 zwischen den beiden Abfragen wurde keine Daten geändert。
例如:事务1第一次查询表中记录总数是100条,事务2在事务1运行期间向表中插入了一条记录。事务1第二次查询表中记录总数时变成了101条。
- 不可重复读(Non-Repeatable Read)
指在一个事务内两次读取到同一条记录,但各自的数据不相同。
例如:事务1第一次读取表中某条记录的某个字段为某值,事务2更新该记录的该字段。事务1第二次读取同一记录,对应的字段值就不同了。
以上三种现象都与事务隔离级别有关,隔离级别越低,这些问题就越容易出现。正确使用事务可以避免这些问题发生。