
文章目錄
- 前言
- 1. Spring概述
- 1.1 介紹
- 2. IoC入門
- 2.1 什么是IoC
- 2.2 IoC入門案例1(基礎案例)
- 2.3 IoC入門案例2(依賴注入)
- 2.4 IoC入門案例3(面向介面編程)
- 2.5 IoC入門案例4(整合JUnit4)
- 3. IoC詳解
- 3.1 Bean的創建
- 3.2 依賴注入(DI)
- 3.2.1 按照名稱注入
- 3.2.2 按照型別注入
- 3.2.3 普通資料注入
- 4 properties資料注入
- 1.1 @Bean(工廠Bean)
- 3.2.5 基本使用:型別注入
- 3.2.6 基本使用:指定名稱注入
- 3.2.7 依賴注入:參考型別
- 3.2.8 依賴注入:簡單型別
- 1.1 Bean的作用域
- 3.3 生命周期
- 3.3.1 實體Bean
- 3.3.2 工廠Bean
- 4. AOP
- 4.1 AOP概述
- 4.1.1 什么是AOP
- 4.1.2 快速入門1
- 4.1.3 AOP作用和優勢
- 4.1.4 快速入門2
- 4.1.5 快速入門3
- 4.1.6 AOP實作方法
- 4.2 相關AOP術語
- 4.3 相關注解
- 4.3.1 切入點運算式
- 4.3.2 通知方法
- 4.3.3 抽取公共 切入點
- 4.4 完整通知演示
- 4.4.1 AOP編程
- 4.4.2 目標介面和類
- 5. 整合MyBatis
- 5.1 環境搭建
- 5.1.1 匯入 pom相關的依賴
- 5.1.2 組態檔
- 5.1.3 創建資料庫和表
- 5.1.4 創建domain
- 5.2 撰寫dao和service
- 5.2.1 撰寫dao介面
- 5.2.2 撰寫service介面
- 5.2.3 撰寫Service實作類
- 5.3 配置類
- 5.3.1 spring配置類
- 5.3.2 mybatis配置類【新內容】
- 5.4 測驗類
- 5.4.1 方式1:整合Junit
- 5.4.2 方式2:手動創建工廠
- 5.4.3 完整的UserService
- 6. 事務管理
- 6.1 案例:轉賬
- 6.1.1 需求描述:
- 6.1.2 環境搭建
- 6.1.3 撰寫domain
- 6.1.4 撰寫dao
- 6.1.5 撰寫service
- 6.1.6 測驗
- l 事務的概述
- 6.2 事務概述
- 6.3 Spring事務相關的術語
- 6.3.1 事務平臺管理器: PlatformTransactionManager
- 6.4 事務入門
- 6.4.1 修改配置類
- 6.4.2 修改Service
- 6.5 事務高級 ( 面試必背 )
- 6.5.1 事務特性:ACID
- 6.5.2 并發訪問問題
- 6.5.3 隔離級別:解決問題
- 6.5.4 術語
- 6.5.5 定義物件:概述 TransactionDefinition
- 6.5.6 定義物件:只讀
- 6.5.7 定義物件:超時
- 6.5.8 定義物件:隔離級別
- 6.5.9 定義物件:傳播行為 ( Spring特有 )
- 7. 附錄
前言
上回為各位分享了《六萬字最全總結Java資料庫編程MyBatis》沒有學過的同學,建議先學MyBatis,這次在此基礎上我們來學習經典框架之Spring!
??爆肝六萬字最全總結Java資料庫編程MyBatis(建議收藏)
相關資料:
檔案:02_Spring組態檔和配置類
1. Spring概述
1.1 介紹
Spring框架是企業使用最多的框架,沒有之一,Spring是一站式框架,稱之為一站式框架的原因是Spring可以整合其他框架,

要學習Spring的內容如下:
l Spring IoC:物件工廠及依賴注入;
l Spring AOP:面向切面編程技術,為Spring事務管理打下基礎,
l Spring Transaction management:Spring事務管理,
l Spring Web MVC(不包含在本課程內,后面單獨學習):簡稱Spring MVC框架,用來簡化JavaWEB開發,當使用Spring MVC框架后,就不用再撰寫Servlet了,也就不再需要itcast-tools工具中BaseServlet類了,
l Spring與其他框架整合:因為我們只學習過MyBatis框架,所以當前我們只學習Spring整合MyBatis框架,
2. IoC入門
2.1 什么是IoC
Spring IoC的核心如下:
l 工廠負責物件生命周期的管理;(spring管理創建與銷毀)
l 物件的依賴由工廠完成注入,(spring維護物件間關系)
Spring提出了物件工廠的概念,由Spring工廠來管理物件的生命周期,所謂物件生命周期指的是從物件的創建一直到物件的銷毀都由Spring來管理,我們無需再自己new物件,而是從Spring工廠中獲取需要的物件,甚至物件的依賴也由工廠來注入,無需手動注入依賴,
Spring工廠是ApplicationContext介面,通常我們使用的是AnnotationConfigApplicationContext類,其中Spring工廠內部是通過Map型別來維護的,
| key | value |
|---|---|
| “userDao1” | UserDao實體 |
| “userService1” | UserService實體 |
| … | … |
當我們需要獲取工廠中的實體時,只需要呼叫工廠的getBean(“id”)即可,
?
@Test
public void test3() {
AnnotationConfigApplicationContext context = ...
UserDao userDao = (UserDao) context.getBean("userDao1");
...
}

2.2 IoC入門案例1(基礎案例)
入門案例1 使用IOC的方式創建UserDao物件 呼叫查詢所有方法
思路:
- 目標類上加@Component
創建UserDao類, 書寫方法 findAll ,在類上添加注解@component(”名字”),用來告知spring可以通過指定名字來創建該UserDao物件
- 配置類添加@Configuration 和 @ComponentScan
創建配置類 [SpringConfiguration,類上添加@Configuration注解和@ComponentScan注解.[(作用是用來告知Spring該類是配置類,并要掃描的包有哪些)]
- 測驗類通過ApplicationContext的getBean(“名字”)獲取物件

案例步驟如下:
l 配置類(SpringConfiguration)
l UserDao類
l UserDaoTest類

2.2.1 下載Spring
官網:http://spring.io/
下載地址:
http://repo.springsource.org/libs-release-local/org/springframework/spring
解壓:(Spring目錄結構:)
docs :API和開發規范.
libs :jar包和原始碼.
schema :約束.

我們上課使用的maven,使用老師發的pom檔案即可.
Pom檔案也可以從本檔案結尾的附錄的pom01-Spring入門拷貝
2.2.2 配置類(SpringConfiguration)
任何Spring專案都建議創建配置類,它提供了Spring工廠最基本的配置資訊,本案例中該類沒有任何內容,只需要添加兩個注解,
SpringConfiguration.java
package com.czxy.comfig;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@ComponentScan(basePackages = {"com.czxy.dao"})
@Configuration
public class SpringConfiguration {
}
l 其中@Configuration注解告知Spring當前類是一個配置類;
l 其中@componentScan注解告知Spring要掃描的包,Spring會掃描并加載指定包下所有類中的注解,
2.2.3 UserDao.java
我們需要在撰寫UserDao類,同時希望Spring去創建該類實體并添加到工廠中,這需要在類上添加@Component注解,同時指定實體的id,Spring會掃描到UserDao類上的@Component注解,
UserDao.java
package com.czxy.dao;
import org.springframework.stereotype.Component;
@Component("ud")
public class UserDao {
public void findAll(){
System.out.println("查詢所有");
}
}
2.2.4 UserDaoTest測驗類
在測驗類中我們需要先創建工廠物件,然后從工廠物件中獲取UserDao物件實體,
UserDaoTest.java
package com.czxy.test;
import com.czxy.comfig.SpringConfiguration;
import com.czxy.dao.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class TestA {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
UserDao userDao = (UserDao) applicationContext.getBean("ud");// new UserDao();
userDao.findAll();
}
}
2.3 IoC入門案例2(依賴注入)
入門案例2中我們需要創建UserService類,但我們知道UserServce一定會依賴UserDao類,然后我們讓Spring工廠幫助我們完成依賴注入,

步驟如下:
l 定義UserService類并添加@Component注解;
l 在UserService類中添加private UserDao userDao依賴;
l 在userDao成員上添加@Resource注解指定依賴,
SpringConfiguration.java
package com.czxy.comfig;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@ComponentScan(basePackages = {"com.czxy.dao","com.czxy.service"})
@Configuration
public class SpringConfiguration {
}
UserService.java
package com.czxy.service;
import com.czxy.dao.UserDao;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component("us")
public class UserService {
@Resource(name = "ud")
private UserDao userDao ;//= new UserDao();
public void findAllUsers(){
System.out.println("開始查找");
userDao.findAll();
System.out.println("查找結束");
}
}
測驗類
@Test
public void test02(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
UserService userService = (UserService) applicationContext.getBean("us");
userService.findAllUsers();
}
測驗結果:

2.4 IoC入門案例3(面向介面編程)
? 入門案例3提供dao的介面和實作類、提供service的介面和實作類,程式之間使用介面,將所有實作類交予spring管理,完成程式間的解耦,


l 步驟如下
n 撰寫UserDao介面和實作類,并在實作類中添加@Component注解
n 撰寫UserService介面和實作類,并在實作類中添加@Component注解
n 在userDao成員變數中添加@Resource注解,注入dao的實作類,
n 撰寫配置類
n 編程測驗類
l dao介面和實作類
public interface UserDao {
public void findAll();
}
@Component("userDaoImpl")
public class UserDaoImplA implements UserDao {
public void findAll(){
System.out.println("A方式 查詢所有");
}
}
l service介面和實作類
public interface UserService {
public void findAllUsers();
}
@Component("userServiceImpl")
public class UserServiceImplA implements UserService {
@Resource(name = "userDaoImpl")
private UserDao userDao ;//= new UserDao();
public void findAllUsers(){
System.out.println("開始查找");
userDao.findAll();
System.out.println("查找結束");
}
}
l 配置類 不變
@ComponentScan(basePackages = {"com.czxy.dao","com.czxy.service"})
@Configuration
public class SpringConfiguration {
}
l 測驗類
@Test
@Test
public void test03(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
UserService userService = (UserService) applicationContext.getBean("userServiceImpl");
userService.findAllUsers();
}
測驗結果:

2.5 IoC入門案例4(整合JUnit4)
l 修改測驗
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={SpringConfigruation.class})
public class UserDaoTest {
@Resource(name="userService1")
private UserService userService;
@Test
public void testFindAll(){
userService.findAll();
}
}
3. IoC詳解
3.1 Bean的創建
前面已經學習了創建Bean的注解@Component,Spring還提供了一些衍生注解,
| 注解 | 描述 |
|---|---|
| @Component | 將修飾的資源交予spring管理,value屬性:為資源命名(唯一標識) |
| @Controller | 衍生注解,與@Component作用和屬性相同,特用于修飾表示層的資源, |
| @Service | 衍生注解,與@Component作用和屬性相同,特用于修飾業務邏輯層的資源, |
| @Repository | 衍生注解,與@Component作用和屬性相同,特用于修飾資料訪問層的資源, |
示例: 分別使用不同名字的注解來設定回應的類
@Repository("userDao1")
public class UserDaoImpl implements UserDao {
public void findAll(){
System.out.println("入門案例");
}
}
@Service("userService1")
public class UserServiceImpl implements UserService{
@Resource(name="userDao1")
private UserDao userDao;
public void findAll(){
System.out.println("user service ...");
userDao.findAll();
}
}
l 以上4個注解修飾的類,我們通常稱為注冊bean,目的是將某類的實體物件,添加到spring容器中,
3.2 依賴注入(DI)
| 注解 | 描述 | 修飾位置 |
|---|---|---|
| @Resource(name=”…”) | 按照指定名稱注入物件 | 欄位、setter方法 |
| @ Resource | 按照型別注入物件 | 欄位、setter方法 |
| @Value | 注入簡單值 | 欄位、setter方法、引數 |
| @PropertySource | 加載properties組態檔 | 類 |
3.2.1 按照名稱注入
示例: 按照名稱來注入userDao物件
?dao
@Repository("userDao1")
public class UserDaoImpl implements UserDao {
public void findAll(){
System.out.println("入門案例");
}
}
?service
@Service("userService1")
public class UserServiceImpl implements UserService{
@Resource(name="userDao1")
private UserDao userDao;
public void findAll(){
System.out.println("user service ...");
userDao.findAll();
}
}
3.2.2 按照型別注入
示例: 分別創建dao ,service ,和測驗類,按照型別注入對應的物件
?dao
@Repository
public class UserDaoImpl implements UserDao {
public void findAll(){
System.out.println("入門案例");
}
}
?service
@Service
public class UserServiceImpl implements UserService{
@Resource
private UserDao userDao;
public void findAll(){
System.out.println("user service ...");
userDao.findAll();
}
}
?測驗
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={SpringConfigruation.class})
public class UserDaoTest {
@Resource
private UserService userService;
@Test
public void testFindAll(){
userService.findAll();
}
}
3.2.3 普通資料注入
示例:字串型別的成員變數和方法引數注入資料.
?固定值注入
public class SpringConfigruation {
@Value("com.mysql.jdbc.Driver")
private String driver;
@Value("jdbc:mysql://127.0.0.1:3306/crm_ssm_v1_0")
public void setUrl(String url){
System.out.println("欄位:" + driver);
System.out.println("方法:" + url);
}
}
?測驗
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={SpringConfigruation.class})
public class UserDaoTest {
@Test
public void testFindAll() throws SQLException{
}
}
4 properties資料注入
需求: 把properties檔案中的資料讀取出來,在測驗類中展示
總體思路:
使用@PropertySource加載properties組態檔,“classpath:”固定前綴,表示從類路徑下加載組態檔,
@Value(${jdbc.driver}) 獲得組態檔中指定key的內容
? 默認:將整個運算式進行注入,及 driver變數的值是 ${jdbc.driver}
? 固定代碼:必須配置PropertySourcesPlaceholderConfigurer實體,
專案結構如下:

jdbc.properties組態檔:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/test1
jdbc.username=root
jdbc.password=1234
?配置類 添加內容
package com.czxy.demo02;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
@Configuration
@PropertySource("classpath:db.properties")
public class SpringConfig02 {
// 在4.2.4版本讀取properties必須寫,必須要寫的固定格式
@Bean
public static PropertySourcesPlaceholderConfigurer create(){
return new PropertySourcesPlaceholderConfigurer();
}
}
測驗類:
package com.czxy.demo02;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig02.class)
public class TestB {
@Value("${jdbc.driver}")
private String driverClassName;
@Value("${jdbc.url}")
private String url;
@Test
public void test01(){
System.out.println("driverClassName="+driverClassName);
System.out.println("url="+url);
}
}
測驗結果:正常獲取資料
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-SIWE7Gtr-1633402543916)(C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps7DBD.tmp.jpg)]
1.1 @Bean(工廠Bean)
把別人創建的類,交給IOC管理可以使用方法配合注解@Bean的方式實作.
通過@Component等注解,將我們自己撰寫的物件配置到spring容器中,
通過@Resource等注解,將我們自己撰寫的物件之間的關系配置到spring容器中,
實際開發中,我們經常會遇到某些類不是我們寫的,此時我們希望通過IOC對這種類進行管理,我們就沒法辦在這個類上加@Component等注解了. 這個時候可以創建一個方法在方法上使用@Bean來實作對這些類物件的管理
3.2.5 基本使用:型別注入
? @Bean用于修飾方法 ,將方法創建的物件添加到spring容器
需求: 假設UserDao不是我們寫的類,無法使用@Component注解,
創建一個方法用于獲取UserDao物件
準備如下幾個類

UserDao:
package com.czxy.demo03;
public class UserDao {
public void findAll(){
System.out.println("查詢所有 ");
}
}
SpringConfig03:
package com.czxy.demo03;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig03 {
@Bean
public UserDao getUserDao(){
return new UserDao();
}
}
測驗類:
package com.czxy.demo03;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig03.class)
public class TestC {
@Resource
private UserDao userDao;
@Test
public void test01(){
userDao.findAll();
}
}
測驗結果:

3.2.6 基本使用:指定名稱注入
上面例子中,在方法上只是書寫了一個@Bean.并沒有給期產生的物件命名如果想命名可以通過如下方式.
@Bean(name=”名字”) 可以為當前物件設定一個名稱,如果沒有使用name設定名稱,默認名為“ 方法名 ”,
需求:
UserDao是個介面,有倆實作類UserDaoImplA和UserDaoImplB, 這三個類假設我們都不能修改.
現在想獲取這倆實作類的物件,交給IOC管理. 設計完成該例子.
專案結構如下:

UserDao介面:
package com.czxy.demo04;
public interface UserDao {
public void findAll();
}
UserDaoImplA實作類:
package com.czxy.demo04;
public class UserDaoImplA implements UserDao {
@Override
public void findAll() {
System.out.println("A 方式實作查詢所有用戶 ");
}
}
UserDaoImplB實作類:
package com.czxy.demo04;
public class UserDaoImplB implements UserDao {
@Override
public void findAll() {
System.out.println("B 方式實作查詢所有用戶 ");
}
}
配置類:
package com.czxy.demo04;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig04 {
@Bean(name ="userDaoImplA" )
public UserDao getUserDaoA(){
return new UserDaoImplA();
}
@Bean(name ="userDaoImplB" )
public UserDao getUserDaoB(){
return new UserDaoImplB();
}
}
測驗類:
package com.czxy.demo04;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig04.class)
public class TestD {
@Resource(name = "userDaoImplB")
private UserDao userDao;
@Test
public void test01(){
userDao.findAll();
}
}
測驗結果:
userDaoImplB對應:

userDaoImplA對應:

3.2.7 依賴注入:參考型別
當某一個方法的引數是一個被IOC管理的物件時,可以通過@Bean的方式,自動注入該物件.
如UserDao物件被IOC管理了. 那么 若有方法 形如testXXX(UserDao userDao) 則可以在方法上添加@Bean,來自動注入UserDao物件.
示例1:
把UserDao交給IOC
在配置類中書寫一個方法show(UserDao userDao),完成自動注入,在測驗類中進行測驗.

代碼詳情:
UserDao
package com.czxy.demo06;
import org.springframework.stereotype.Repository;
@Repository
public class UserDao {
public void findAll(){
System.out.println("查詢所有");
}
}
配置類:SpringConfig06
package com.czxy.demo06;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import javax.annotation.Resource;
@Configuration
@ComponentScan(basePackages = "com.czxy.demo06")
public class SpringConfig06 {
@Bean
public String show(UserDao userDao){
System.out.println("完成自動注入:"+userDao);
//測驗呼叫userDao方法
userDao.findAll();
return null;
}
}
測驗類:
package com.czxy.demo06;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig06.class)
public class TestA1 {
@Test
public void test02(){
//無需書寫任何代碼, 單純執行
//該方法就會看到自動注入UserDao
}
}
測驗結果:

可以看到 完成了自動注入.
示例2:
把UserDao物件存放到spring容器中, 然后再UserService方法中要使用UserDao,此時可以直接把UserDao當做引數傳遞到方法中
`

配置類:
package com.czxy.demo02.config;
import com.czxy.demo02.dao.UserDao;
import com.czxy.demo02.dao.UserDaoImpl;
import com.czxy.demo02.service.UserService;
import com.czxy.demo02.service.UserServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = {"com.czxy.demo02"})
public class SpringConfiguration {
@Bean
public UserDao getUserDao(){
return new UserDaoImpl();
}
@Bean
public UserService getUserService(UserDao userDao){
System.out.println(userDao);
return new UserServiceImpl();
}
}
?測驗類
package com.czxy.demo02.test;
import com.czxy.demo02.config.SpringConfiguration;
import com.czxy.demo02.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class TestA {
@Resource
public UserService userService;
@Test
public void test01(){
System.out.println(userService);
}
}
測驗結果:

3.2.8 依賴注入:簡單型別
需求: 把properties檔案中的字串 以簡單型別的方式添加到引數中 列印對應的值.
l 配置類

相應代碼:
@PropertySource("classpath:db.properties")
public class SpringConfiguration2 {
@Bean
public static PropertySourcesPlaceholderConfigurer create(){
return new PropertySourcesPlaceholderConfigurer();
}
@Bean
public UserService createUserService(@Value("${jdbc.username}") String name, @Value("${jdbc.password}") String pwd){
System.out.println("name = "+name+" pwd ="+pwd);
return new UserServiceImpl();
}
}
l 測驗類

代碼:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration2.class)
public class TestB {
@Resource
private UserService userService;
@Test
public void test01(){
System.out.println(userService);
}
}
測驗結果:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-3KBzWRNK-1633402543928)(C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps7DD8.tmp.jpg)]
1.1 Bean的作用域
? 通過@Scope可以Bean的作用域,也就是通知spring是否每次都創建新物件,
| 注解 | 描述 | 取值 |
|---|---|---|
| @Scope | 用于設定Bean的作用域 | singleton :默認值,單例的.prototype :多例的. |
單例模式: 整個IOC容器中只有該物體類的一個物件
多例模式: 整個IOC容器中該物體類有多個物件


示例:
搞一個User類,在配置類中設定單例模式和多例模式,創建兩個物件觀察效果.
配置類:

測驗類:

單例模式結果: 地址編號相同,說明是用的同一個物件

保持測驗類不變,只更改為多例模式

測驗結果:列印的兩個地址編號不同,說明IOC容器中有多個物件
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-WWrI1INl-1633402543932)(C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps7DEF.tmp.jpg)]
l 其他取值(了解)
-
request :WEB專案中,Spring創建一個Bean的物件,將物件存入到request域中.
-
session :WEB專案中,Spring創建一個Bean的物件,將物件存入到session域中.
-
globalSession :WEB專案中,應用在Portlet環境.如果沒有Portlet環境那么globalSession相當于session
3.3 生命周期
? 生命周期指 單實體 物件由創建到銷毀的整個程序,
? 此處,主要研究初始化方法和銷毀方法,
3.3.1 實體Bean
實體Bean同時2個注解,來控制類中那個方法初始化方法,那個方法是銷毀方法,
| 注解 | 描述 |
|---|---|
| @PostConstruct | 初始化方法,專案啟動時執行,只會被呼叫一次, |
| @PreDestroy | 銷毀方法,專案關閉時執行,只會被呼叫一次, |
?實體Dog
@Component
public class Dog {
@PostConstruct
public void init(){
System.out.println("狗 初始化");
}
public void eat(){
System.out.println("狗 吃吃吃..");
}
@PreDestroy
public void destory(){
System.out.println("狗 銷毀 ");
}
}
?配置類
@ComponentScan(basePackages={"com.czxy.domain"})
public class SpringConfigruation {
}
?測驗類
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class TestC {
@Resource
private Dog dog;
@Test
public void test01(){
dog.eat();
}
}
測驗結果 :

3.3.2 工廠Bean
工廠Bean通過@Bean的2個屬性完 成初始化和銷毀方法的配置,
? initMethod:配置初始化方法
? destroyMethod:配置銷毀方法
物體類:
public class Cat {
public void init(){
System.out.println("貓 初始化");
}
public void eat(){
System.out.println("貓 吃吃吃..");
}
public void destory(){
System.out.println("貓 銷毀 ");
}
}
?配置類
@Configuration
@ComponentScan(basePackages = {"com.czxy.demo02"})
public class SpringConfiguration {
@Bean(initMethod = "init" ,destroyMethod = "destory")
public Cat getCat(){
return new Cat();
}
}
測驗類:
@Resource
private Cat cat;
@Test
public void test02(){
cat.eat();
}
測驗結果:

4. AOP
4.1 AOP概述
4.1.1 什么是AOP
? AOP:全稱是Aspect Oriented Programming即:面向切面編程,
? 面向切面編程,通過預編譯方式和運行期動態代理實作程式功能的統一維護的一種技術,
? 簡單的說它就是把我們程式重復的代碼抽取出來,在需要執行的時候,使用代理的技術,在不修改原來代碼的基礎上,對已有方法進行增強,

4.1.2 快速入門1
需求:
User類中有方法eat . 現在在不修改eat方法的前提下,對eat進行增強. 增強的內容是,在執行eat之前,先執行 沐浴更衣 這個動作.
實作思路:
\1. 搭建基本的測驗 可以在測驗類中執行eat方法
\2. 創建切面類,指明對eat方法進行增強;

具體代碼如下: 在書寫代碼之前記得在pom檔案添加spring相關的依賴.

User類
@Component
public class User {
public void eat(){
System.out.println("吃吃吃");
}
}
配置類:
@Configuration //設定為 配置類
@ComponentScan(basePackages = {"com.czxy.demo01"}) // 設定要掃描的包
@EnableAspectJAutoProxy // 設定 開啟切面
public class SpringConfig01 {
}
切面類:
@Component
@Aspect
public class MyAspect01 {
@Before("execution(public void com.czxy.demo01.User.eat())")
public void bf01(){
System.out.println("沐浴更衣 ");
}
}
測驗類:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes ={SpringConfig01.class})
public class TestA {
@Resource
private User user;
@Test
public void test01(){
user.eat();
}
}
執行結果:

4.1.3 AOP作用和優勢
l 作用:
\4. 在程式運行期間,不修改原始碼對已有方法進行增強,
l 優勢:
\5. 減少重復代碼
\6. 提高開發效率
\7. 維護方便
4.1.4 快速入門2
需求: 使用AOP 對UserService介面的兩個方法進行增強. 在方法執行之前,開啟事務,在方法執行之后關閉事務.
專案結構:

具體代碼:
Pom中需要添加aop相關的依賴

UserService介面: 介面中提供兩個方法
public interface UserService {
public void addUser();
public void delUser();
}
實作類UserServiceImpl
@Service
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("添加用戶 ");
}
@Override
public void delUser() {
System.out.println("洗掉用戶");
}
}
配置類:
@Configuration
@ComponentScan(basePackages = "com.czxy.demo02")
@EnableAspectJAutoProxy
public class SpringConfiguration2 {
}
切面類MyAspect02:
@Component
@Aspect
public class MyAspact02 {
@Before("execution(public void com.czxy.demo02.UserService.*())")
public void bf(){
System.out.println("開啟事務");
}
@After("execution(public void com.czxy.demo02.UserService.*())")
public void af(){
System.out.println("關閉事務");
}
}
測驗類:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration2.class)
public class TestB {
@Resource
private UserService userService;
@Test
public void test01(){
userService.addUser();
System.out.println("----------");
userService.delUser();
}
}
測驗結果:

4.1.5 快速入門3
需求: 使用AOP 對UserService和BookService介面的方法進行增強.

4.1.6 AOP實作方法
Spring AOP 主要通過2種代理技術來實作:動態代理、CGLIB
? 動態代理:用于對介面+實作類情況進行代理,
@EnableAspectJAutoProxy(proxyTargetClass = false )
? CGLIB:用于對僅有類情況進行代理,
@EnableAspectJAutoProxy(proxyTargetClass = true )
4.2 相關AOP術語
Target( *目標物件 *):
? 代理的目標物件,通俗點講:你需要增強的類,這個類就是目標物件
? 例如:UserServiceImpl
Joinpoint( *連接點 *):
? 所謂連接點是指可能被增強的位置,在spring中,AOP是對方法進行增強,這個位置/時機可以是方法前或者方法后,或者出例外的時候,
? 例如:addUser()方法執行之前的位置 或者 addUser()方法執行之后的位置 或者 AddUser出例外的時候
Pointcut( *切入點 *):
? 所謂切入點是指我們要對哪些Joinpoint進行攔截的定義,通俗講: 確定了在哪個位置進行增強
? 例如:@Before(“execution(public void com.czxy.demo02.UserService.addUser())”)
Advice( *通知 */ *增強 *): 具體要干的事情
? 所謂通知是指攔截到Joinpoint之后所要做的事情就是通知,
? 通知的型別:前置通知,后置通知,例外通知,最終通知,環繞通知,
? 例如:bf()、af()
Aspect( *切面 *):
? 是切入點和通知的結合,
? 例如:MyAspect類
Proxy *(代理) *:
? 一個類被AOP增強后,就產生一個結果代理類,


4.3 相關注解
| 注解 | 描述 | |
|---|---|---|
| @Aspect | 把當前類宣告成切面類 | |
| @Before | 把當前方法看成是前置通知 | |
| @AfterReturning | 把當前方法看成是后置通知, | |
| @AfterThrowing | 把當前方法看成是例外通知 | |
| @After | 把當前方法看成是最終通知 | |
| @Around | 把當前方法看成是環繞通知 | |
| @Pointcut | 指定切入點運算式 |
4.3.1 切入點運算式
execution:
匹配方法的執行(常用)
execution(運算式)
運算式語法:execution([修飾符] 回傳值型別 包名.類名.方法名(引數))
寫法說明:
全匹配方式:
public void com.itheima.service.impl.CustomerServiceImpl.saveCustomer()
訪問修飾符可以省略
void com.itheima.service.impl.CustomerServiceImpl.saveCustomer()
回傳值可以使用*號,表示任意回傳值
* com.itheima.service.impl.CustomerServiceImpl.saveCustomer()
包名可以使用*號,表示任意包,但是有幾級包,需要寫幾個*
* *.*.*.*.CustomerServiceImpl.saveCustomer()
使用..來表示當前包,及其子包
* com..CustomerServiceImpl.saveCustomer()
類名可以使用*號,表示任意類
* com..*.saveCustomer()
方法名可以使用*號,表示任意方法
* com..*.*()
引數串列可以使用*,表示引數可以是任意資料型別,但是必須有引數
* com..*.*(*)
引數串列可以使用..表示有無引數均可,有引數可以是任意型別
* com..*.*(..)
全通配方式:
* *..*.*(..)
4.3.2 通知方法
l 方式1:沒有引數形式
@Before("execution(public void com.czxy.demo01.User.eat())")
public void bf01(){
System.out.println("洗手 ");
}
執行效果:

l 方式2:獲得引數JoinPoint,從而獲得目標類,目標方法等資訊
@Before("execution(public void com.czxy.demo01.User.eat())")
public void bf01(JoinPoint jp){
System.out.println("洗手 ");
System.out.println("目標類:"+jp.getTarget());//獲取目標類
System.out.println("切入點:"+jp.getSignature());//獲取切入點
}
執行效果:

l 方式3:環繞通知獲得引數ProceedingJoinPoint,對目標方法的執行進行控制,
@Around("execution(public void com.czxy.demo01.User.eat())")
public void ar(ProceedingJoinPoint jp) throws Throwable {
System.out.println("洗手 ");
jp.proceed();//執行 eat方法
System.out.println("擦嘴");
}
執行效果:

4.3.3 抽取公共 切入點
使用@PointCut可以將公共的切入點進行抽取,一般都宣告在私有方法上,
在通知注解使用,通過方法名參考,
@Pointcut("execution(* com.czxy.service..*.*(..))")
private void myPointcut(){
}
@Before("myPointcut()")
public void bf(JoinPoint joinPoint){
System.out.println("前置..." + joinPoint.getTarget());
System.out.println("前置..." + joinPoint.getSignature().getName());
}
@AfterReturning("myPointcut()")
public void af(){
System.out.println("后置...");
}
4.4 完整通知演示
4.4.1 AOP編程
l 撰寫需要對目標類,增量的類和方法(可以復制)
@Pointcut("execution(* com.czxy.service..*.*(..))")
private void myPointcut(){
}
@Before("myPointcut()")
public void bf(JoinPoint joinPoint){
System.out.println("前置..." + joinPoint.getTarget());
System.out.println("前置..." + joinPoint.getSignature().getName());
}
@AfterReturning("myPointcut()")
public void af(){
System.out.println("后置...");
}
l 測驗
? 
4.4.2 目標介面和類
?介面
public interface UserService {
public void saveUser();
public String updateUser();
}
?實作類
@Service
public class UserServiceImpl implements UserService {
@Override
public void saveUser() {
System.out.println("save");
}
@Override
public String updateUser() {
System.out.println("update");
return "abc";
}
}
4.4.3配置類
@ComponentScan(basePackages={"com.czxy"})
@EnableAspectJAutoProxy
public class SpringConfigruation {
}
4.4.4切面類
@Component
@Aspect
public class MyAspect2 {
@Pointcut("execution(* com.czxy.service..*.*(..))")
private void myPointcut(){
}
@Before("myPointcut()")
public void bf(JoinPoint joinPoint){
System.out.println("前置..." + joinPoint.getTarget());
System.out.println("前置..." + joinPoint.getSignature().getName());
}
@AfterReturning(value="myPointcut()",returning="ret")
public void ar(JoinPoint joinPoint , Object ret){
System.out.println("后置..." + ret);
}
@Around("myPointcut()")
public void ar(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("環繞前");
joinPoint.proceed(); //執行目標方法
System.out.println("環繞后");
}
@AfterThrowing(value="myPointcut()",throwing="ex")
public void at(JoinPoint joinPoint ,Throwable ex){
System.out.println("例外:" + ex.getMessage());
}
@After("myPointcut()")
public void af(){
System.out.println("最終");
}
}
4.4.5測驗類
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={SpringConfigruation.class})
public class UserDaoTest {
@Resource
private UserService userService;
@Test
public void testFindAll() throws SQLException{
userService.saveUser();
int i = 1/0;
userService.updateUser();
}
}
5. 整合MyBatis
之前使用的持久層框架是MyBatis, 現在將Mybatis框架整合到Spring框架中,由Spring統一管理.其核心思路是把Mapper對應的實作類物件存放在IOC容器中.
需求:
通過Spring+Mybatis整合,把一個用戶的資訊添加到資料庫中.
實作步驟:
-
環境搭建
-
撰寫Dao和Service
-
書寫配置類
-
測驗
完整的專案結構如下:

5.1 環境搭建
5.1.1 匯入 pom相關的依賴
<properties>
<spring.version>4.2.4.RELEASE</spring.version>
</properties>
<dependencies>
<!-- spring start -->
<!--spring core start-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring core end-->
<!--spring aop start-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spirng aop end-->
<!--spring aspects start-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring aspects end-->
<!--spring instrumentation start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring instrumentation end-->
<!--spring messaging start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring messaging end-->
<!--spring data access start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring data access end-->
<!--spring web start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc-portlet</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring web end -->
<!--spring test start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring test end -->
<!-- spring end -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>3.7.5</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
</dependencies>
5.1.2 組態檔

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/test1
jdbc.username=root
jdbc.password=1234
5.1.3 創建資料庫和表
CREATE TABLE USER(
uid VARCHAR(32) PRIMARY KEY,
username VARCHAR(50),
PASSWORD VARCHAR(32)
)
5.1.4 創建domain

public class User {
@Id
private String uid;
private String username;
private String password;
//getter和setter方法
//....
}
5.2 撰寫dao和service
5.2.1 撰寫dao介面

package com.czxy.dao;
import com.czxy.domain.User;
import tk.mybatis.mapper.common.Mapper;
public interface UserMapper extends Mapper<User> {
}
5.2.2 撰寫service介面

package com.czxy.service;
import com.czxy.domain.User;
public interface UserService {
public User findByPrimaryKey(String uid);
public void insertUser(User user);
}
5.2.3 撰寫Service實作類

package com.czxy.service.impl;
import com.czxy.dao.UserMapper;
import com.czxy.domain.User;
import com.czxy.service.UserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
@Service
@Transactional
public class UserServiceImpl implements UserService {
@Resource
private UserMapper userMapper;
@Override
public User findByPrimaryKey(String uid) {
return userMapper.selectByPrimaryKey(uid);
}
@Override
public void insertUser(User user) {
userMapper.insert(user);
}
}
5.3 配置類
5.3.1 spring配置類
1.配置注解
? 1.1 掃描注解包
? 1.2加載properties檔案
? 1.3 開啟注解事務支持
2.獲得properties資料(實作類、@Value)
3.配置資料源DataSource
4.配置事務管理器(DataSourceTransactionManager)
package com.czxy.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
import javax.annotation.Resource;
import javax.sql.DataSource;
@Configuration
@ComponentScan(basePackages = {"com.czxy"})
@EnableTransactionManagement
@PropertySource(value = "classpath:db.properties")
public class SpringConfig {
// 4.2.4版本 固定配置
@Bean
public static PropertySourcesPlaceholderConfigurer create(){
return new PropertySourcesPlaceholderConfigurer();
}
//讀取資料庫相關配置
@Value("${jdbc.driver}")
private String driverClass;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
//資料源使用德魯伊連接池
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driverClass);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
return ds;
}
// 開啟事務管理器
@Bean
@Resource
public DataSourceTransactionManager txManager(DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
}
5.3.2 mybatis配置類【新內容】
如下代碼直接當做配置類拷貝即可.
1.配置session工廠,spring和MyBatis整合時,通過SqlSessionFactoryBean獲得SqlSessionFactory
? SqlSessionFactoryBean只能加載mapper映射檔案
? 注解開發需要加載Mapper類,故需要對mapper進行掃描
2.配置映射掃描器
package com.czxy.config;
import com.github.pagehelper.PageHelper;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import tk.mybatis.spring.mapper.MapperScannerConfigurer;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Properties;
/💃
* Spring整合MyBatis的配置類
* @author Administrator
*/
// 宣告
@Configuration
public class MyBatisConfig {
/💃
* 構建SessionFactory物件,SessionFactory可以創建Session物件,最后使用Session操作資料庫
* @param dataSource
* @return
* @throws Exception
*/
@Bean
@Resource
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
// 1.通過工廠bean創建物件,最后需要呼叫 getObject()獲得具體的物件
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
// 1.1 設定資料源
factoryBean.setDataSource(dataSource);
// 1.2 設定別名包掃描
factoryBean.setTypeAliasesPackage("com.czxy.domain");
// 1.3 全域配置:駝峰映射
org.apache.ibatis.session.Configuration config = new org.apache.ibatis.session.Configuration();
config.setMapUnderscoreToCamelCase(true);
factoryBean.setConfiguration(config);
// 2 插件配置
// 2.1 分頁插件
PageHelper pageHelper = new PageHelper();
Properties pageProps = new Properties();
pageProps.setProperty("dialect", "mysql");
pageProps.setProperty("rowBoundsWithCount", "true");
pageHelper.setProperties(pageProps);
factoryBean.setPlugins(new Interceptor[] { pageHelper });
// 3 通過工廠bean獲得 sqlSessionFactory
return factoryBean.getObject();
}
/💃
* 掃描Dao的包,查找各種XxxMapper介面,創建好UserMapper等物件存入到IOC的容器中
* @return
*/
@Bean
public MapperScannerConfigurer mapperScanner() {
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setBasePackage("com.czxy.dao");
return configurer;
}
}
5.4 測驗類
5.4.1 方式1:整合Junit
package com.czxy.test;
import com.czxy.config.MyBatisConfig;
import com.czxy.config.SpringConfig;
import com.czxy.domain.User;
import com.czxy.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfig.class,MyBatisConfig.class})
public class TestA {
@Resource
private UserService userService;
@Test
public void test01(){
User user = new User("u001","張三豐","123");
userService.insertUser(user);
System.out.println("添加完畢");
}
}
測驗結果: 成功添加用戶資訊


5.4.2 方式2:手動創建工廠
public class TestB {
public static void main(String[] args) {
//1.創建工廠,設定兩個配置類
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class,MyBatisConfig.class);
//2.從工廠獲取需要的物件
UserService userService = applicationContext.getBean(UserService.class);
//3.執行陳述句
User user = new User("u800","zhangsan","123");
userService.insertUser(user);
System.out.println("添加完畢");
}
}
5.4.3 完整的UserService
userService:
public interface UserService {
void addUser(User user);
void updateUser(User user);
void delUser(String uid);
User findByPrimaryKey(String uid);
List<User> findAll();
List<User> findByPage();
}
userServiceImpl:
@Service
@Transactional // 第五節講解
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
public void addUser(User user) {
userMapper.insert(user);
}
public void updateUser(User user) {
userMapper.updateByPrimaryKey(user);
}
public void delUser(String uid) {
userMapper.deleteByPrimaryKey(uid);
}
public User findByPrimaryKey(String uid) {
return userMapper.selectByPrimaryKey(uid);
}
public List<User> findAll() {
return userMapper.selectAll();
}
public List<User> findByPage() {
// PageHelper
// 第一個引數:第幾頁
// 第二個引數:獲取條數 ,PageHelper這個代碼后的第一個sql陳述句進行分頁
PageHelper.startPage(1, 2);
// 查找
// userMapper.selectAll();
List<User> list = userMapper.select(null);
// 封裝到pageInfo
PageInfo<User> info = new PageInfo<User>(list);
return info.getList();
}
}
1 什么是Spring
2 什么是IOC
3 什么是AOP
在不改變原代碼的情況下,對已有功能進行增強
目標物件
連接點
切入點
通知/增強(前置通知、后置通知、環繞通知…)
切面
代理
4 常用注解
IOC:
@Component
@Repository
@Service
@Controller
@Resource
@Autowired
@Bean
? @RunWith
? @ContextConfiguration
? @Configuration
AOP:@After @Before @AfterReturning @AfterThrowing @Around @Joinpoint
6. 事務管理
6.1 案例:轉賬
6.1.1 需求描述:
完成轉賬功能, 根據兩個賬戶的id和要轉賬的錢money,對其中一個id的錢-money,對另一個id的錢+money.
分析:
轉賬功能 需要由兩個動作完成.
-
賬戶1減錢
-
賬戶2加錢
減錢:根據賬戶id對錢數 減
加錢:根據賬戶id 對錢數 加
總體思路:
\1. SM整合環境搭建好.
\2. 在service中提供轉賬功能.
\3. 測驗類中測驗.轉賬功能
專案結構如下:

6.1.2 環境搭建
l 步驟1:匯入jar包坐標
l 步驟2:組態檔

l 步驟3:資料庫和表
CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(40),
money FLOAT
);
INSERT INTO account(NAME,money) VALUES('jack',10);
INSERT INTO account(NAME,money) VALUES('rose',10);
6.1.3 撰寫domain
public class Account {
@Id
private Integer id;
private String name;
private Double money;
//省略getter和setter方法
}
6.1.4 撰寫dao
public interface AccountMapper extends Mapper<Account> {
}
6.1.5 撰寫service
AccountService介面:
public interface AccountService {
public void change(Integer inId,Integer outId,Double money);
}
AccountServiceImpl實作類:
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountMapper accountMapper;
public void change(Integer inId, Integer outId, Double money) {
//加錢
Account account = accountMapper.selectByPrimaryKey(inId);
account.setMoney(account.getMoney()+money);
accountMapper.updateByPrimaryKey(account);
//減錢
Account account1 = accountMapper.selectByPrimaryKey(outId);
account1.setMoney(account1.getMoney()-money);
accountMapper.updateByPrimaryKey(account1);
}
}
6.1.6 測驗
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfig.class,MyBatisConfig.class})
public class TestA {
@Resource
private AccountService accountService;
@Test
public void test01(){
accountService.change(1,2,1d);
System.out.println("完畢");
}
}
測驗結果: 執行成功結果正確

修改Service中的代碼,繼續測驗:
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountMapper accountMapper;
public void change(Integer inId, Integer outId, Double money) {
Account account = accountMapper.selectByPrimaryKey(inId);
account.setMoney(account.getMoney()+money);
accountMapper.updateByPrimaryKey(account);
int i=1/0;
Account account1 = accountMapper.selectByPrimaryKey(outId);
account1.setMoney(account1.getMoney()-money);
accountMapper.updateByPrimaryKey(account1);
}
}
結果: 一個賬號加錢了, 一個賬號沒減錢

l 事務的概述
n 事務指的是邏輯上的一組操作,組成這組操作的各個單元要么全都成功,要么全都失敗.
n 事務作用:保證一組操作要么全都成功,對資料庫進行完整更新,要么在某一個動作失敗的時候讓資料恢復原狀,不會引起不完整的修改,
6.2 事務概述
? JavaEE體系進行分層開發,事務處理位于業務層,Spring提供了分層設計 業務層 的事務處理解決方案,
? spring的事務控制是基于AOP的,也就是spring提供了實作類對我們的業務方法進行增強,完成事務具體的操作,
6.3 Spring事務相關的術語
6.3.1 事務平臺管理器: PlatformTransactionManager
? spring通過事務管理器來管理事務,
? 事務管理器PlatformTransactionManager提供了事務需要的基本操作,

| 實作類 | 描述 |
|---|---|
| DataSourceTransactionManager | 使用JdbcTemplate或MyBatis需要的事務管理器 |

6.4 事務入門
6.4.1 修改配置類
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountMapper accountMapper;
public void change(Integer inId, Integer outId, Double money) {
Account account = accountMapper.selectByPrimaryKey(inId);
account.setMoney(account.getMoney()+money);
accountMapper.updateByPrimaryKey(account);
int i=1/0;
Account account1 = accountMapper.selectByPrimaryKey(outId);
account1.setMoney(account1.getMoney()-money);
accountMapper.updateByPrimaryKey(account1);
}
}
6.4.2 修改Service
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountMapper accountMapper;
public void change(Integer inId, Integer outId, Double money) {
Account account = accountMapper.selectByPrimaryKey(inId);
account.setMoney(account.getMoney()+money);
accountMapper.updateByPrimaryKey(account);
int i=1/0;
Account account1 = accountMapper.selectByPrimaryKey(outId);
account1.setMoney(account1.getMoney()-money);
accountMapper.updateByPrimaryKey(account1);
}
}
6.5 事務高級 ( 面試必背 )
6.5.1 事務特性:ACID
l 原子性(Atomicity)原子性是指事務是一個不可分割的作業單位,事務中的操作要么都成功,要么都失敗,
l 一致性(Consistency)事務前后資料的完整性必須保持一致,
l 隔離性(Isolation)事務的隔離性是指多個用戶并發訪問資料庫時,一個用戶的事務不能被其它用戶的事務干擾,多個并發事務之間資料要相互隔離,
l 持久性(Durability)持久性是指一個事務一旦被提交,它對資料庫中資料的改變就是永久性的,接下來即使資料庫發生故障也不應該對其有任何影響,
6.5.2 并發訪問問題
如果不考慮隔離性,事務存在并發訪問問題,
臟讀:讀未提交
不可重復度:讀已提交(update)兩次讀取的結果不一致
幻讀/虛讀:讀已提交(insert)兩次讀取的結果不一致
\1. 臟讀:(讀未提交)一個事務讀到了另一個事務未提交的資料.

\2. 不可重復讀(讀已提交):一個事務讀到了另一個事務已經提交(update)的資料,引發另一個事務,在事務中的多次查詢結果不一致,(要保證同一個事物的多次查詢同一個資料,結果一致)

\3. 虛讀 /幻讀:(讀已提交)一個事務讀到了另一個事務已經提交(insert)的資料,導致另一個事務,在事務中多次查詢的結果不一致,(資料量不同)

嚴重性: 臟讀 > 不可重復讀 >虛讀(幻讀)
6.5.3 隔離級別:解決問題
l 資料庫規范規定了4種隔離級別,分別用于描述兩個事務并發的所有情況,
\1. read uncommitted 讀未提交,一個事務讀到另一個事務沒有提交的資料,
a) 存在:3個問題(臟讀、不可重復讀、虛讀),
b) 解決:0個問題
效率最高,引發所有讀問題
基本不用
\2. read committed 讀已提交,一個事務讀到另一個事務已經提交的資料,
a) 存在:2個問題(不可重復讀、虛讀),
b) 解決:1個問題(臟讀)
如果要 效率,那么選擇這個read committed
\3. repeatable read :可重復讀,在一個事務中讀到的資料資訊始終保持一致,無論另一個事務是否提交,
a) 存在:1個問題(虛讀),
b) 解決:2個問題(臟讀、不可重復讀)
如果 要求安全,選擇這個repeatable read
虛讀的問題可以通程序式來規避:
-
事務剛開啟時,可以count(*)
-
事務要關閉時,可以count(*)
-
比對,如果兩次資料一致,說明沒有虛讀
\4. serializable 串行化,同時只能執行一個事務,相當于事務中的單執行緒,
a) 存在:0個問題,
b) 解決:1個問題(臟讀、不可重復讀、虛讀)
效率最低,安全性最高,基本不用
l 安全和性能對比
n 安全性:serializable > repeatable read > read committed > read uncommitted
n 性能 : serializable < repeatable read < read committed < read uncommitted
l 常見資料庫的默認隔離級別:
n MySql:repeatable read 安全,本身做的優化比較好
n Oracle:read committed 效率
6.5.4 術語
事務:

TransactionDefinition:事務的定義資訊物件,需要知道,方便知道事務有哪些設定項,
TransactionStatus:事務的狀態物件,spring內部使用的物件,不需要關注,
6.5.5 定義物件:概述 TransactionDefinition

通過分析事務定義資訊物件,spring事務定義主要涉及以下4方面:隔離級別、傳播行為、超時、只讀
6.5.6 定義物件:只讀
開發中,查詢資料,不會伴隨增刪改,所以建議查詢時設定為只讀,
| 注解 | 描述 |
|---|---|
| @Transactional(readOnly=true) | 只讀事務,DQL使用 |
| @Transactional(readOnly=false) | 默認值,不是只讀事務,可以進行增刪改操作,DML使用 |
6.5.7 定義物件:超時
默認值是-1,沒有超時限制,如果有,以秒為單位進行設定,(一般不設定)
| 注解 | 描述 |
|---|---|
| @Transactional(timeout=60) | 設定超時為60秒,如果還沒有操作結束,將拋例外, |
6.5.8 定義物件:隔離級別
事務隔離級別反映事務提交并發訪問時的處理態度,
| 注解 | 描述 |
|---|---|
| @Transactional(isolation=Isolation.DEFAULT) | 默認級別 |
| @Transactional(isolation=Isolation.READ_UNCOMMITTED) | 讀未提交 |
| @Transactional(isolation=Isolation.READ_COMMITTED) | 讀已提交 oracle |
| @Transactional(isolation=Isolation.REPEATABLE_READ) | 可重復讀 mysql |
| @Transactional(isolation=Isolation.SERIALIZABLE) | 串行化 |

6.5.9 定義物件:傳播行為 ( Spring特有 )
傳播行為:業務A使用了業務B,AB之間事務共享問題,就是事務的傳播行為,
spring中事務的傳播行為共7種,
| 注解 | 描述 |
|---|---|
| @Transactional(propagation=Propagation.REQUIRED) | 默認值,支持當前事務,如果當前沒有事務,就新建一個事務 |
| @Transactional(propagation=Propagation.SUPPORTS) | 支持當前事務,如果當前沒有事務,就以非事務方式執行 |
| @Transactional(propagation=Propagation.MANDATORY) | 支持當前事務,如果當前沒有事務,就拋出例外 |
| @Transactional(propagation=Propagation.REQUIRES_NEW) | 新建事務,如果當前存在事務,把當前事務掛起 |
| @Transactional(propagation=Propagation.NOT_SUPPORTED) | 以非事務方式執行操作,如果當前存在事務,就把當前事務掛起 |
| @Transactional(propagation=Propagation.NEVER) | 以非事務方式執行,如果當前存在事務,則拋出例外 |
| @Transactional(propagation=Propagation.NESTED) | 如果當前存在事務,則在嵌套事務內執行,如果當前沒有事務,則執行REQUIRED類似的操作 |
7. 附錄
Pom01-Spring入門
<properties>
<spring.version>4.2.4.RELEASE</spring.version>
</properties>
<!-- spring start -->
<!--spring core start-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring core end-->
<!--spring aop start-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spirng aop end-->
<!--spring aspects start-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring aspects end-->
<!--spring instrumentation start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring instrumentation end-->
<!--spring messaging start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring messaging end-->
<!--spring data access start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring data access end-->
<!--spring web start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc-portlet</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring web end -->
<!--spring test start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring test end -->
<!-- spring end -->
rsion>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring core end-->
<!--spring aop start-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spirng aop end-->
<!--spring aspects start-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring aspects end-->
<!--spring instrumentation start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring instrumentation end-->
<!--spring messaging start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring messaging end-->
<!--spring data access start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring data access end-->
<!--spring web start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc-portlet</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring web end -->
<!--spring test start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring test end -->
<!-- spring end -->
后記
📢博客主頁:https://manor.blog.csdn.net
📢歡迎點贊 👍 收藏 ?留言 📝 如有錯誤敬請指正!
📢本文由 manor 原創,首發于 CSDN博客🙉
📢Hadoop系列文章會每天更新!?
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/305671.html
標籤:java
