
1.spring概念
spring框架概述
1.spring是一個輕量級的開源的Javaee框架
2.spring可以解決企業應用開發的復雜性
3.spring有兩個核心部分:IOC和AOP
(1)IOC英文全稱Inversion of Control:控制反轉,把創建物件的程序交給spring框架進行管理
(2)AOP英文全稱Aspect-Oriented Programming:面向切面編程,不修改源代碼進行功能的增強
4.spring的特點
(1)方便解耦,簡化開發
(2)AOP編程支持
(3)方便程式的測驗
(4)方便和其他框架進行整合
(5)方便進行事務操作
(6)降低API開發難度
入門案例
先到官網下載jar包
www.spring.io ----> projects ----> spring framework ----> learn ----> 選擇版本進行下載(也可以直接使用maven)
1.創建一個普通的Java工程
2.匯入相關的jar包

3.創建一個物體類User,在里面寫一個方法add()
public class User {
public void add() {
System.out.println("add......");
}
}
4.創建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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置User物件的創建 -->
<bean id="user" class="cn.pdsu.wbb.entity.User"></bean>
</beans>
5.進行測驗
import cn.pdsu.wbb.entity.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test01 {
@Test
public void testAdd() {
// 加載組態檔
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml") ;
// 獲取配置創建的物件
User user = context.getBean("user", User.class);
System.out.println(user);
user.add();
}
}
2.IOC容器
(1)IOC的底層原理
1.什么是IOC?
(1)控制反轉,把物件的創建和物件之間呼叫的程序交給spring進行管理
(2)使用IOC的目的:降低耦合度
(3)上面的入門案例就是IOC將進行實作的
2.IOC的底層原理
(1)xml決議、工廠模式、反射
工廠模式:

(2)IOC介面(BeanFactory)
1.IOC的思想基于IOC的容器完成,IOC容器底層就是物件工廠
2.spring提供IOC容器實作兩種方式(兩個介面):
(1)BeanFactory:IOC容器基本實作,是由spring內部使用的介面,不提供開發人員使用
BeanFactory在加載組態檔的時候不回去創建物件,只會在使用時創建物件(2)ApplicationContext:BeanFactory介面的子介面,提供了更多更強大的功能,一般由開發人員進行使用
ApplicationContext在加載組態檔時就會把組態檔中的物件進行創建
public class Test01 {
@Test
public void testAdd() {
// 加載組態檔
// ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml") ;
BeanFactory context= new ClassPathXmlApplicationContext("bean1.xml") ;
// 獲取配置創建的物件
User user = context.getBean("user", User.class);
System.out.println(user);
user.add();
}
}
(3)ApplicationContext中的介面
1.FileSystemXmlApplicationContext:需要寫出檔案的帶盤符路徑(檔案的全路徑)
2.ClassPathXmlApplicationContext:在src目錄下時直接寫出檔案名即可
(2)IOC操作Bean管理
1.什么是bean管理
(1)spring創建物件
(2)spring注入屬性
3.Bean管理基于xml組態檔進行實作
(1)基于xml方式創建物件
<!-- 配置User物件創建 -->
<bean id="user" class="cn.pdsu.wbb.entity.User">
①在spring組態檔中使用bean標簽,標簽中添加對應的屬性就可以實作物件的創建
②在bean標簽中常用的屬性
id屬性:獲取物件的唯一標識
class屬性:類的全路徑
③創建物件時默認執行無參的構造方法
當我們在User類中創建一個有引數的構造方法后,沒有無參構造,再次創建物件,它會提示在User類中沒有對應的方法,不能創建物件
public class User {
private String name ;
public User(String name) {
this.name = name ;
}
public void add() {
System.out.println("add......");
}
}

(2)基于xml方式注入屬性
①DI:依賴注入,就是注入屬性(注入屬性要在創建物件的基礎之上完成)
第一種注入方式:使用set方法進行注入
1.創建類,定義其屬性和對應的set方法
/**
* 演示使用set方法進行注入屬性
*/
public class Book {
// 設定屬性
private String name ;
private String author ;
// 創建set方法
public void setName(String name) {
this.name = name;
}
public void setAuthor(String author) {
this.author = author;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
'}';
}
public void show() {
System.out.println("name=" + name + ", author=" + author);
}
}
2.在spring組態檔中配置物件創建,配置屬性的注入
<!-- set方法注入屬性 -->
<bean id="book" class="cn.pdsu.wbb.entity.Book">
<!--
使用property完成屬性注入
name:表示類中屬性的名稱
value:表示向屬性中注入的值
-->
<property name="name" value="西游記"></property>
<property name="author" value="吳承恩"></property>
</bean>
3.進行方法的測驗
import cn.pdsu.wbb.entity.Book;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test01 {
@Test
public void testBook() {
// 加載組態檔
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml") ;
// 獲取配置創建的物件
Book book = context.getBean("book", Book.class);
System.out.println(book);
book.show();
}
}
運行結果截圖

第二種注入方式:通過有參構造進行注入
1.創建類,定義屬性,創建有引數的構造方法
s.name = name;
this.address = address;
}
@Override
public String toString() {
return "Order{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
'}';
}
public void show() {
System.out.println("name=" + name + ",address=" + address);
}
}
2.在spring檔案中進行配置
<!-- 使用有參構造進行屬性的注入 -->
<bean id="order" class="cn.pdsu.wbb.entity.Order">
<constructor-arg name="name" value="電腦"></constructor-arg>
<constructor-arg name="address" value="北京"></constructor-arg>
</bean>
還可以在constructor-arg使用index屬性代替name,0表示類第一個屬性
<constructor-arg index="0" value="電腦"></constructor-arg>
<constructor-arg index="1" value="北京"></constructor-arg>
3.測驗
import cn.pdsu.wbb.entity.Order;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test01 {
@Test
public void testOrder() {
// 加載組態檔
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml") ;
// 獲取配置創建的物件
Order order = context.getBean("order", Order.class);
System.out.println(order);
order.show();
}
}
4.運行結果

p名稱空間注入(本質上還是set注入,可以用于簡化xml配置方式)
第一步,在組態檔中添加p名稱空間
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
第二步,進行屬性注入,在bean標簽中進行操作
<!-- p名稱空間注入 -->
<bean id="book" class="cn.pdsu.wbb.entity.Book" p:name="紅樓夢" p:author="曹雪芹"></bean>
1.IOC操作Bean管理(xml注入其他屬性)
(1).字面量
(1)null值
<property name="author">
<null></null>
</property>
(2)屬性值包含特殊符號
當代碼如下時會報錯,原因是含有‘<’、‘>’,
<property name="author" value="<<南京>>"></property>
1.將特殊符號進行轉義
2.把帶特殊符號的內容寫到CDATA中,CDATA的格式 <![CDATA[要輸出的內容]]>
<property name="author">
<value><![CDATA[<<南京>>]]></value>
</property>

(2).注入屬性—外部bean
(1)創建兩個類service類和dao類
import cn.pdsu.wbb.dao.UserDao;
public class UserService {
// 創建UserDao對應的屬性,生成set方法
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add() {
System.out.println("service add......");
userDao.update();
}
}
public interface UserDao {
void update();
}
public class UserDaoImpl implements UserDao{
@Override
public void update() {
System.out.println("userDaoImpl update......");
}
}
(2)在service中呼叫dao里面的方法
(3)在spring組態檔中進行配置
<!-- 1.service和dao物件的創建 -->
<bean id="userService" class="cn.pdsu.wbb.service.UserService">
<!--
注入userDao物件
name屬性:類里面的屬性名稱
ref屬性:創建userDao物件bean標簽屬性值
-->
<property name="userDao" ref="userDao"></property>
</bean>
<bean id="userDao" class="cn.pdsu.wbb.dao.UserDaoImpl"></bean>
測驗
import cn.pdsu.wbb.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test02 {
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml") ;
UserService userService = context.getBean("userService",UserService.class) ;
userService.add();
}
}
結果

(3).注入屬性—內部bean和級聯注入
(1)一對多關系:部門和員工
一個部門有多個員工,一個員工屬于一個部門
(2)在物體類中表示一對多的關系,員工表示所屬部門用物件形式進行表示
// 部門類
public class Dept {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Dept{" +
"name='" + name + '\'' +
'}';
}
}
// 員工類
public class Emp {
private String name;
private String gender;
// 員工屬于某一個部門,用物件形式進行標識
private Dept dept ;
public void setName(String name) {
this.name = name;
}
public void setGender(String gender) {
this.gender = gender;
}
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Emp{" +
"name='" + name + '\'' +
", gender='" + gender + '\'' +
", dept=" + dept +
'}';
}
}
(3)在spring組態檔中進行相關配置
<!-- 內部bean -->
<bean id="emp" class="cn.pdsu.wbb.entity.Emp">
<!-- 設定兩個普通屬性 -->
<property name="name" value="張三"></property>
<property name="gender" value="男"></property>
<!-- 設定物件型別屬性 -->
<property name="dept">
<bean id="dept" class="cn.pdsu.wbb.entity.Dept">
<property name="name" value="財務部"></property>
</bean>
</property>
</bean>
(4)測驗、結果
@Test
public void test1() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml") ;
Emp emp = context.getBean("emp", Emp.class) ;
System.out.println(emp);
}

級聯賦值
第一種寫法
<bean id="emp" class="cn.pdsu.wbb.entity.Emp">
<!-- 設定兩個普通屬性 -->
<property name="name" value="張三"></property>
<property name="gender" value="男"></property>
<!-- 設定物件型別屬性 -->
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="cn.pdsu.wbb.entity.Dept">
<property name="name" value="安保部"></property>
</bean>
第二種寫法(這種方法是先創建了物件,get拿到物件再進行賦值,所以需要設定要獲取屬性的get方法)
<bean id="emp" class="cn.pdsu.wbb.entity.Emp">
<!-- 設定兩個普通屬性 -->
<property name="name" value="張三"></property>
<property name="gender" value="男"></property>
<!-- 設定物件型別屬性 -->
<property name="dept" ref="dept"></property>
<property name="dept.name" value="技術部"></property>
</bean>
<bean id="dept" class="cn.pdsu.wbb.entity.Dept">
<property name="name" value=""></property>
</bean>
2.IOC操作Bean管理(xml注入集合屬性)
(1)注入普通屬性集合
創建一個類,包含陣列、list集合、map集合、set集合4種型別屬性,并生成set方法
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Student {
// 陣列型別的屬性
private String[] courses;
// list集合型別的屬性
private List<String> list ;
// map集合型別的屬性
private Map<String,String> map;
// set集合型別的屬性
private Set<String> set;
public void setCourses(String[] courses) {
this.courses = courses;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public void setSet(Set<String> set) {
this.set = set;
}
@Override
public String toString() {
return "Student{" +
"courses=" + Arrays.toString(courses) +
"\n, list=" + list +
"\n, map=" + map +
"\n, set=" + set +
'}';
}
}
在spring組態檔中進行配置
<!-- 集合型別屬性注入 -->
<bean id="student" class="cn.pdsu.wbb.collectiontype.Student">
<!-- 陣列型別屬性注入 -->
<property name="courses">
<array>
<value>Java課程</value>
<value>JDBC課程</value>
</array>
</property>
<!-- list集合型別屬性注入 -->
<property name="list">
<list>
<value>張三</value>
<value>李四</value>
</list>
</property>
<!-- map集合型別屬性注入 -->
<property name="map">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="PHP" value="php"></entry>
</map>
</property>
<!-- set集合型別屬性注入 -->
<property name="set">
<set>
<value>12345</value>
<value>上山打老虎</value>
</set>
</property>
</bean>
測驗、結果
@Test
public void show() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml") ;
Student student = context.getBean("student",Student.class) ;
System.out.println(student);
}

(2)注入物件屬性集合
創建一個課程類,在Student類中設定List集合型別的屬性
public class Course {
private String name ;
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Course{" +
"name='" + name + '\'' +
'}';
}
}
private List<Course> list1 ;
public void setList1(List<Course> list1) {
this.list1 = list1;
}
在spring組態檔中進行配置
<!-- 注入list集合屬性,值是物件 -->
<property name="list1">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
<!-- 創建多個物件 -->
<bean id="course1" class="cn.pdsu.wbb.entity.Course">
<property name="name" value="Spring"></property>
</bean>
<bean id="course2" class="cn.pdsu.wbb.entity.Course">
<property name="name" value="SpringMVC"></property>
</bean>
把集合注入的部分抽取出來
(1)在spring組態檔中引入名稱空間util
<?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:util="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
</beans>
創建一個Book類
import java.util.List;
public class Book {
private List<String> list;
public void setList(List<String> list) {
this.list = list;
}
@Override
public String toString() {
return "Book{" +
"list=" + list +
'}';
}
}
在spring組態檔中進行配置
<!-- 提取list集合型別屬性注入 -->
<util:list id="bookList">
<value>西游記</value>
<value>三國演義</value>
<value>紅樓夢</value>
</util:list>
<!-- 提取list集合型別屬性注入使用 -->
<bean id="book" class="cn.pdsu.wbb.collectiontype.Book">
<property name="list" ref="bookList"></property>
</bean>
測驗結果

3.IOC操作Bean管理(FactoryBean)
1.Spring中有兩種bean,一種是普通bean,一種是工廠bean(FactoryBean)
1.普通bean
在組態檔中定義的bean型別就是回傳值型別(我們上述的bean都屬于普通bean)
2.工廠bean
在組態檔中定義的bean型別可以和回傳值型別不同
(1)創建類,讓這個類作為工廠bean,實作介面FactoryBean
(2)實作介面中的方法,在實作的方法中定義回傳的bean型別
import cn.pdsu.wbb.entity.Course;
import org.springframework.beans.factory.FactoryBean;
public class MyBean implements FactoryBean<Course> {
// 定義回傳bean
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setName("course");
return course;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
在spring組態檔中進行配置
<bean id="myBean" class="cn.pdsu.wbb.factorybean.MyBean"></bean>
測驗類、結果
// 回傳值型別是Course,但bean name是myBean
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean6.xml") ;
Course course = context.getBean("myBean", Course.class) ;
System.out.println(course);
}

4.IOC操作bean管理(bean的作用域)
1.在spring中,設定創建bean實體是單實體還是多實體
2.在默認情況下,bean是單實體
驗證默認情況下的bean是單實體還是多實體
創建一個類
public class People{
}
在spring組態檔中對其進行實體化
<bean id="people" class="cn.pdsu.wbb.entity.People"></bean>
測驗、結果
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean6.xml") ;
People people1 = context.getBean("people", People.class) ;
People people2 = context.getBean("people", People.class) ;
System.out.println(people1);
System.out.println(people2);
}
可以看到,所輸出的結果是同一個物件

如何設定bean是單實體還是多實體
在spring組態檔bean標簽中有一個scope屬性用于設定單實體還是多實體
屬性值:
singleton,表示創建單實體物件
prototype,表示創建多實體物件
設定多實體物件
<bean id="people" class="cn.pdsu.wbb.entity.People" scope="prototype"></bean>
再次測驗輸出,可以看到是兩個不同的物件的地址

singleton和prototype的區別
(1)singleton是單實體,prototype是多實體
(2)設定scope值是singleton時,在加載spring組態檔時就會創建單實體物件
設定scope值是prototype時,在呼叫getBean方法時創建多實體物件
5.IOC操作bean管理(bean的生命周期)
(1)生命周期的概念
從物件的創建到物件的銷毀
(2)bean的生命周期
(1)通過構造器創建bean實體(無參構造)
(2)為bean的屬性設定值和對其他bean參考(呼叫set方法)
(3)呼叫bean的初始化方法(需要進行配置)
(4)bean可以進行使用了(物件獲取到了)
(5)當容器關閉時,呼叫bean的銷毀方法(銷毀方法需要進行配置)
創建一個類
public class Orders {
private String orderName ;
public Orders() {
System.out.println("第一步,執行無參構造創建bean實體");
}
public void setOrderName(String orderName) {
this.orderName = orderName;
System.out.println("第二步,呼叫set方法為bean屬性賦值");
}
@Override
public String toString() {
return "Orders{" +
"orderName='" + orderName + '\'' +
'}';
}
// 創建初始化方法
public void initMethod() {
System.out.println("第三步,執行初始化方法");
}
// 創建銷毀方法
public void destroyMethod() {
System.out.println("第五步,執行銷毀方法");
}
}
在spring組態檔中進行配置
<!-- 將初始化方法和銷毀的方法配置到xml檔案中 -->
<bean id="orders" class="beanlife.Orders" init-method="initMethod" destroy-method="destroyMethod">
<property name="orderName" value="電腦"></property>
</bean>
測驗、結果
@Test
public void testBean() {
ApplicationContext context = new ClassPathXmlApplicationContext("xml/bean5.xml") ;
Orders orders = context.getBean("orders" , Orders.class) ;
System.out.println("第四步,獲取創建的bean物件");
// 手動銷毀bean實體,close()方法
// applicationContext介面中沒有close方法,需要用其子介面實作向下轉型呼叫close方法
((ClassPathXmlApplicationContext)context).close();
}

(3)bean的后置處理器,七步
(1)通過構造器創建bean實體(無參構造)
(2)為bean的屬性賦值(set方法)和對其他bean的參考
(3)把bean實體傳遞到bean的后置處理器的方法
(4)呼叫bean的初始化方法(初始化方法需要進行配置)
(5)把bean實體傳遞到bean的后置處理器的方法
(6)bean創建完成可以使用(物件已獲取到)
(7)當容器關閉時,呼叫bean的銷毀方法(銷毀方法需要進行配置)
演示添加后置處理器的效果
(1)創建類,實作BeanPostProcessor,創建后置處理器
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class BeanPost implements BeanPostProcessor {
// 初始化前執行
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化前執行");
return bean ;
}
// 初始化后執行
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化后執行");
return bean ;
}
}
在spring組態檔中進行配置,進行這個配置后,它會為當前組態檔中的所有bean實體都添加上后置處理器
<bean id="beanPost" class="beanlife.BeanPost"></bean>
運行結果

6.IOC操作Bean管理(xml自動裝配)
1.什么是手動裝配和自動裝配?
手動裝配:通過value/ref屬性設定屬性值的方式
自動裝配:根據指定的裝配的規則(屬性名稱或屬性值),spring自動匹配的屬性注入
手動裝配
<!-- 手動裝配 -->
<bean id="dept" class="cn.pdsu.wbb.outowire.Dept"></bean>
<bean id="emp" class="cn.pdsu.wbb.outowire.Emp">
<property name="dept" ref="dept"></property>
</bean>
自動裝配,在bean標簽中存在一個autowire屬性,其用來配置bean的自動裝配
<bean id="dept" class="cn.pdsu.wbb.outowire.Dept"></bean>
<bean id="emp" class="cn.pdsu.wbb.outowire.Emp" autowire="byName"></bean>
autowire屬性有兩個常用值:
byName:根據屬性名稱進行注入,注入的bean的id值應于類中的屬性名相同
byType:根據屬性型別進行注入,但是當容器中有多個型別相同的物件時,byType就不能再使用
7.IOC操作Bean管理(引入外部屬性檔案)
1.配置資料庫資訊
(1)配置德魯伊連接池
(2)引入德魯伊連接池依賴jar包

<!-- 直接配置連接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/userDb"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
2.引入外部屬性檔案配置資料庫連接池
1)創建外部屬性檔案,properties格式檔案,寫入資料庫資訊

(2)把外部properties屬性檔案引入到spring組態檔中
*引入context名稱空間
<?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"
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">
*把外部properties屬性檔案引入到spring組態檔中
<!-- 把外部properties屬性檔案引入到spring組態檔中 -->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!-- 2.配置連接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.userName}"></property>
<property name="password" value="${prop.password}"></property>
</bean>
4.Bean管理基于注解進行實作
IOC操作Bean管理(基于注解方式)
1.什么是注解
(1)注解是代碼中的特殊標記,格式:@注解名稱(屬性名稱=屬性值,屬性名稱=屬性值)
(2)使用注解時,注解作用在類、方法或屬性上面
(3)使用注解的目的是簡化xml配置
2.Spring針對Bean管理中創建物件提供的注解
(1)@Component:普通的注解
(2)@Service:建議用于service
(3)@Controller:建議用于web層
(4)@Repository:建議用于dao層
上面的四個注解功能一樣,都可以用于創建bean實體
3.基于注解方式實作物件的創建
(1)引入依賴

(2)開啟組件掃描(去看看哪個類上面有注解,有的話就去創建物件)
<context:component-scan base-package="cn.pdsu.wbb"></context:component-scan>
在context:component-scan標簽中有一個base-package屬性,用于配置需要掃描的包
要掃描多個包的兩種寫法
1.包名,包名... 包與包之間用逗號','進行隔開
2.直接填寫要掃描的包的上層目錄
(3)創建類,在類上面添加注解
在注解后括號中的value只可以不寫,其默認值就是首字母小寫的類名稱 PeopleService -> peopleService
@Component(value = "peopleService") // 這個注解相當于我們之前在xml檔案中所寫的<bean id="userService" class="...."></bean>
public class PeopleService {
public void add() {
System.out.println("add......");
}
}
測驗、結果
@Test
public void testService() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean9.xml") ;
PeopleService peopleService = context.getBean("peopleService" , PeopleService.class) ;
System.out.println(peopleService);
peopleService.add();
}

4.開啟組件掃描的細節配置
當我們將一個包寫入到base-package中時,它會默認掃描包中的所有類
但在context:component-scan標簽中有一個user-default-filters屬性,它默認值為true,表示掃描所給包中的所有檔案
當我們設定其為false時,要用到一個context:include-filter標簽進行配置需要掃描的內容
如示例1所示只掃描帶Controller注解的類 include-filter 僅包括
<!-- 示例1 -->
<context:component-scan base-package="annotate.test">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
如示例2所示只不掃描帶Controller注解的類 exclude-filter 不包括
<!-- 示例2 -->
<context:component-scan base-package="annotate.test">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
5.基于注解方式實作屬性的注入
(1)@AutoWored:根據屬性型別進行自動裝配
第一步 創建service類和dao類,把service和dao物件創建,在service和dao類中添加創建物件注解
第二步 在service類中注入dao物件,在service類中添加dao型別屬性,在屬性上面使用注解
import cn.pdsu.wbb.dao.PeopleDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@Service(value = "peopleService")
public class PeopleService {
// 這里不需要添加set方法
@Autowired // 添加注入屬性注解
private PeopleDao peopleDao ;
public void add() {
System.out.println("add......");
people.add();
}
}
public interface PeopleDao {
public void add();
}
import org.springframework.stereotype.Repository;
@Repository
public class PeopleDaoImpl implements PeopleDao {
@Override
public void add() {
System.out.println("add......");
}
}
測驗、結果
@Test
public void testService() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean9.xml") ;
PeopleService peopleService = context.getBean("peopleService" , PeopleService.class) ;
System.out.println(peopleService);
peopleService.add();
}

(2)@Qualifier:根據屬性名稱進行注入
@Qualifier注解需要和@AutoWired一起使用
當一個介面有多個實作類時,需要用到Qualifier的名稱注入找到你所要注入的類
@Autowired // 添加注入屬性注解
@Qualifier(value="peopleDaoImpl") // 根據名稱進行注入
private PeopleDao peopleDao ;
(3)@Resource:可以根據型別注入,也可以根據名稱注入
// @Resource // 根據型別進行注入
@Resource(name = "userDaoImpl")
private PeopleDao peopleDao ;
Resource注解是javax.annotation.Resource;包下的
它不屬于spring,是javax擴展包下的注解,spring官方不建議用@Resource
(4)@Value:注入普通型別屬性
在屬性上添加@Value注解,它的屬性value是我們要設定的屬性值
@Value(value = "tom")
private String name ;
6.完全注解開發(不使用xml組態檔)
(1)創建配置類,替代xml組態檔
添加注解@Configuration作為配置類替代xml組態檔
添加@ComponentScanc創建組件掃描 basePackage中填寫要掃描的包(陣列形式)
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration // 作為注解類代替xml組態檔
@ComponentScan(basePackages = {"cn.pdsu.wbb"}) // 注解掃描
public class SpringConfig {
}
(2)撰寫測驗類
ClassPathXmlApplicationContext("bean9.xml")改為
AnnotationConfigApplicationContext(SpringConfig.class)
@Test
public void test() {
// 換成配置類的實作
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class) ;
PeopleService peopleService = context.getBean("peopleService " , PeopleService.class) ;
System.out.println(peopleService );
peopleService .add();
}
3.aop
1.AOP(概念)
(1)什么是AOP
1.aop意為面向切面編程,利用aop可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率
2.通俗的講就是通過不修改源代碼的方式再主干功能中添加新的功能
3.使用登錄的例子來說明aop

2.AOP底層原理
1.AOP底層使用動態代理
第一種,有介面情況,使用JDK動態代理
// 介面
interface UserDao {
public void login();
}
// 實作介面
class UserDaoImpl UserDao() {
public void login() {
// 登錄實作程序
}
}
JDK動態代理
創建UserDao介面實作代理物件,通過代理物件去增強類里面的方法
第二種,沒有介面的情況
class User {
public void add() {
......
}
}
要想增強其方法,我們可以創建它的子類
class Person extends User{
public void add() {
super.add
// 增強的邏輯
......
}
}
2.AOP(JDK動態代理)
1.使用JDK動態代理,使用Proxy類中的方法創建代理物件
java.lang.reflect包下的Proxy類
呼叫newProxyInstance方法
newProxyInstance(classloader loader , 類<?>[] interface , InvocationHandler h)
方法中的三個引數
第一個引數,類加載器
第二個引數,增強方法所在的類,這個類實作的介面,支持多個介面
第三個引數,實作InvocationHandler這個介面,創建代理物件,寫增強的方法
2.撰寫JDK動態代理的代碼
(1)創建介面,自定義方法
public interface UserDao {
public int add(int a, int b) ;
public String update(String str) ;
}
(2)創建介面實作類,實作方法
public class UserDaoImpl implements UserDao{
@Override
public int add(int a, int b) {
System.out.println("add.....");
return a+b;
}
@Override
public String update(String str) {
System.out.println("update....");
return str;
}
}
(3)使用Proxy類實作增強功能
import cn.pdsu.dff.dao.UserDao;
import cn.pdsu.dff.dao.UserDaoImpl;
import cn.pdsu.wbb.entity.User;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class JDKProxy {
public static void main(String[] args) {
// 創建介面實作類代理物件
Class[] interfaces = { UserDao.class } ;
UserDaoImpl userDao = new UserDaoImpl();
UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),interfaces ,new UserDaoProxy(userDao) ) ;
int result = dao.add(1,2) ;
System.out.println(result);
}
}
// 創建代理物件代碼
class UserDaoProxy implements InvocationHandler {
// 把創建的是誰的代理物件,將其傳過來
// 有參構造傳遞
private Object obj ;
public UserDaoProxy(Object obj) {
this.obj=obj ;
}
// 增強邏輯
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 增強add方法
// 在方法之前增強的一個步驟
System.out.println("方法執行之前...." + method.getName() + ":傳遞的引數..." + Arrays.toString(args));
// 被增強的方法執行
Object res = method.invoke(obj , args) ;
// 方法執行后
System.out.println("方法執行后...." + obj);
return res;
}
}
3.AOP(術語)
class User {
add() {}
update() {}
select() {}
delete() {}
}
1.連接點
類中可以增強的方法
在上面的User類中,add、update、select、delete方法都可以被增強,他們都是連接點
2.切入點
實際被增強的方法,比如說我只增強了add方法,那么add就是切入點
3.通知(增強)
實際增強的邏輯部分被稱為通知(增強)
通知(增強)有多種型別
①前置通知:方法前執行
②后置通知:方法后執行
③環繞通知:方法前后都執行
④例外通知:出現例外會執行
⑤最終通知:類似于try...catch中的finally
4.切面
切面是一個動作,把通知應用到切入點的程序叫做切面
4.AOP操作(準備)
1.Spring框架一般都是給予AspectJ實作AOP操作的
AspectJ不是Spring的組成部分,其獨立于AOP框架,一般把AspectJ和Spring框架一起使用,進行AOP操作
2.基于AspectJ實作AOP操作
1)基于xml組態檔實作
2)基于注解方式實作(使用)
3.引入依賴

4.切入點運算式
(1)切入點運算式的作用:知道對哪個類的哪個方法進行增強
(2)語法結構:
execution([權限修飾符][回傳型別] [類全路徑][方法名稱] ([引數串列]))
權限修飾符:public/private/…,可以省略不寫默認是public
例:對cn.edu.pdsu.People類里面的add方法進行增強
execution(*cn.edu.pdsu.People.add(..))
(這里的權限修飾符被省略了,其中‘ * ’表示匹配所有回傳值型別,‘. .’表示引數串列,引數串列就是兩個點)
例:對cn.edu.pdsu.People類里面的全部方法進行增強
execution(* cn.edu.pdsu.People.*(..))
例:對cn.edu.pdsu包下的所有類的所有方法進行增強
execution(* cn.edu.pdsu.*.*(..))
5.AOP操作(AspectJ注解)
1.創建類,在類中定義方法
public class User {
public void add() {
System.out.println("add......");
}
}
2.創建增強類(撰寫增強邏輯)
在增強類中定義方法,不同的類表示不同的通知型別
// 增強類
public class UserProxy {
// 前置通知
public void before() {
System.out.println("before......");
}
}
3.進行通知的配置
(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"
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">
<!-- 引入context、aop名稱空間 -->
<!-- 開啟注解掃描 -->
<context:component-scan base-package="cn.pdsu.dff"></context:component-scan>
</beans>
(2)使用注解創建User和UserProxy物件


(3)在增強類上面添加注解@Aspect
// 被增強類
@Component
@Aspect
public class User {
public void add() {
System.out.println("add......");
}
}
(4)在spring組態檔中開啟生成代理物件
<!-- 開啟AspectJ生成代理物件 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
4.配置不同型別的通知
(1)在增強類的里面,在作為通知方法上面添加通知型別注解,使用切入點運算式配置
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
// 增強類
@Component
@Aspect
public class UserProxy {
// 前置通知
// @Before注解表示前置通知
@Before(value = "execution(* cn.pdsu.dff.dao.User.add(..))")
public void before() {
System.out.println("before......");
}
// 最終通知
@After(value = "execution(* cn.pdsu.dff.dao.User.add(..))")
public void after() {
System.out.println("after......");
}
// 后置通知(回傳通知)
@AfterReturning(value = "execution(* cn.pdsu.dff.dao.User.add(..))")
public void afterReturning() {
System.out.println("afterReturning......");
}
// 例外通知
@AfterThrowing(value = "execution(* cn.pdsu.dff.dao.User.add(..))")
public void afterThrowing() {
System.out.println("afterThrowing......");
}
// 環繞通知
@Around(value = "execution(* cn.pdsu.dff.dao.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("around前......");
// 被增強的方法執行
proceedingJoinPoint.proceed() ;
System.out.println("around后......");
}
}
測驗、結果
import cn.pdsu.dff.dao.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAop {
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean10.xml") ;
User user = context.getBean("user",User.class) ;
user.add();
}
}
此時的例外通知并未執行

我們來人為的制造一個例外
public void add() {
int a = 10 / 0 ; // 例外
System.out.println("add......");
}
例外通知執行,afterReturning、around后沒執行

5.相同切入點的抽取
// 相同切入點的抽取
@Pointcut(value ="execution(* cn.pdsu.dff.dao.User.add(..))")
public void pointDemo() {
}
// 前置通知
// @Before注解表示前置通知
@Before(value = "pointDemo()")
public void before() {
System.out.println("before......");
}
這樣做的好處是當我們需要進行切入運算式的修改時,只需要修改一處即可
6.設定增強類的優先級
有多個增強類對同一個方法做增強,可以設定增強類的優先級
(1)在增強類的上面添加注解@Order(數字),數字越小,優先級越高就會被越先執行
@Component
@Aspect
@Order(1)
public class PeopleProxy {
7.完全使用注解開發
創建配置類,不需要創建xml組態檔
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan(basePackages = {"cn.pdsu.dff"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop {
}
6.AOP操作(AspectJ組態檔)
1.創建增強類和被增強類,創建方法
public class Book {
public void buy() {
System.out.println("buy....");
}
}
public class BookProxy {
public void before() {
System.out.println("before....");
}
}
2.在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:aop="http://www.springframework.org/schema/aop"
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">
<!-- 創建物件 -->
<bean id="book" class="cn.pdsu.dff.aopxml.Book"></bean>
<bean id="bookProxy" class="cn.pdsu.dff.aopxml.BookProxy"></bean>
3.在spring組態檔中配置切入點
<!-- 配置aop的增強 -->
<aop:config>
<!-- 切入點 -->
<aop:pointcut id="p" expression="execution(* cn.pdsu.dff.aopxml.Book.buy(..))"/>
<!-- 配置切面 -->
<aop:aspect ref="bookProxy">
<!-- 增強作用在具體的方法上 -->
<aop:before method="before" pointcut-ref="p"></aop:before>
</aop:aspect>
</aop:config>
4.測驗、結果
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean11.xml") ;
Book book = context.getBean("book",Book.class) ;
book.buy();
}

4.jdbcTemplate
1.JdbcTemplate(概念和準備)
1.什么是JdbcTemplate
Spring框架對JDBC進行的封裝,使用JdbcTemplate方便實作對資料庫的操作
2.準備作業
(1)引入依賴

(2)在spring組態檔中配置連接池
<!-- 資料庫連接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close">
<property name="url" value="jdbc:mysql:///book_db" />
<property name="username" value="root" />
<property name="password" value="123456" />
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
</bean>
(3)配置JdbcTemplate物件,注入DataSource
<!-- JdbcTemplate物件 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 注入dataSource -->
<property name="dataSource" ref="dataSource"></property>
</bean>
(4)創建service和dao類,在dao注入JdbcTemplate物件
組態檔
<!-- 開啟組件掃描 -->
<context:component-scan base-package="cn.pdsu.wbb"></context:component-scan>
@Service
public class BookService {
// 注入dao
@Autowired
private BookDao bookDao ;
}
public interface BookDao {
}
@Service
public class BookDaoImpl implements BookDao{
// 注入JdbcTemplate對象
@Autowired
private JdbcTemplate jdbcTemplate ;
}
3.JdbcTemplate操作資料庫(添加)
(1)創建物體類Book
public class Book {
private String id ;
private String name ;
private String status ;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
@Override
public String toString() {
return "Book{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", status='" + status + '\'' +
'}';
}
}
(2)撰寫service和dao
(1)在dao中進行資料庫添加操作
(2)呼叫jdbcTemplate物件里面的update方法實作添加操作

兩個引數:
第一個引數:sql陳述句
第二個引數:可變引數,設定sql陳述句的值
@Service
public class BookService {
// 注入dao
@Autowired
private BookDao bookDao ;
// 添加的方法
public void addBook(Book book) {
bookDao.addBook(book);
}
}
public interface BookDao {
void addBook(Book book);
}
@Service
public class BookDaoImpl implements BookDao{
@Autowired
private JdbcTemplate jdbcTemplate ;
@Override
public void addBook(Book book) {
// 創建sql陳述句
String sql = "insert into book values(?,?,?)" ;
// 呼叫方法實作
int update = jdbcTemplate.update(sql,book.getId(),book.getName(),book.getStatus()) ;
System.out.println(update);
}
}
(3)測驗、結果
public class TestBook {
@Test
public void Test() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml") ;
BookService bookService = context.getBean("bookService" , BookService.class) ;
Book book = new Book();
book.setId("1");
book.setName("zhangsan");
book.setStatus("a");
bookService.addBook(book);
}
}

4.JdbcTemplate操作資料庫(修改、洗掉)
// 修改的方法
@Override
public void update(Book book) {
String sql = "update book set name=? , status=? where id=?" ;
int update = jdbcTemplate.update(sql,book.getName(),book.getStatus(),book.getId()) ;
System.out.println(update);
}
// 洗掉的方法
@Override
public void delete(Book book) {
String sql = "delete from book where id=?" ;
int update = jdbcTemplate.update(sql,book.getId()) ;
System.out.println(update);
}
測驗修改操作、結果
@Test
public void Test() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml") ;
BookService bookService = context.getBean("bookService" , BookService.class) ;
Book book = new Book();
book.setId("1");
book.setName("lisi");
book.setStatus("good");
bookService.update(book);
}

測驗洗掉操作、結果
@Test
public void Test() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml") ;
BookService bookService = context.getBean("bookService" , BookService.class) ;
Book book = new Book();
book.setId("1");
bookService.deleteBook(book);
}

5.JdbcTemplate操作資料庫(查詢回傳某個值)
1.查詢表中有多少條資料,回傳某個值
2.使用JdbcTemplate實作資料查詢回傳某個值的代碼

兩個引數
第一個引數表示sql陳述句
第二個引數表示回傳型別的Class
@Override
public int findCount() {
String sql = "select count(*) from book" ;
int count = jdbcTemplate.queryForObject(sql,Integer.class);
return count;
}
6.JdbcTemplate操作資料庫(查詢回傳物件)
1.場景:查詢圖書的詳情頁面
2.JdbcTemplate實作查詢回傳物件

三個引數
第一個引數表示sql陳述句
第二個引數表示RowMapper,是一個介面,回傳不同型別的資料,使用這個介面里面的實作類完成資料的封裝
第三個引數表示sql陳述句的值
@Override
public Book findObject(int id) {
String sql = "select * from book where id=?" ;
Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book>(Book.class),id) ;
return book;
}

7.JdbcTemplate操作資料庫(查詢回傳集合)
1.場景:查詢圖書串列、分頁
2.呼叫jdbcTemplate方法實作查詢回傳集合
有三個引數
第一個引數:sql陳述句
第二個引數:RowMapper,是一個介面,回傳不同型別的資料,使用這個介面里面的實作類完成資料的封裝
第三個引數:sql陳述句的值
// 回傳list集合
@Override
public List<Book> findAll() {
String sql = "select * from book" ;
List<Book> list = jdbcTemplate.query(sql,new BeanPropertyRowMapper<Book>(Book.class));
return list;
}

8.JdbcTemplate操作資料庫(批量操作)
1.批量操作
(1)JdbcTemplate批量添加

兩個引數
第一個引數:sql陳述句
第二個引數:List集合,添加多條記錄資料
// 批量添加
@Override
public void batchAdd(List<Object[]> batchArgs) {
String sql = "insert into book value(?,?,?)" ;
int[] ints = jdbcTemplate.batchUpdate(sql,batchArgs) ;
System.out.println(ints);
}
測驗
@Test
public void Test() {
ApplicationContext context = new ClassPathXmlApplicationContext("cn\\pdsu\\jdbcTemplate\\xml\\bean1.xml") ;
BookService bookService = context.getBean("bookService" , BookService.class) ;
List<Object[]> batchArgs = new ArrayList<>() ;
Object[] o1 = {3,"java","a"};
Object[] o2 = {4,"c","b"};
Object[] o3 = {5,"python","c"};
batchArgs.add(o1);
batchArgs.add(o2);
batchArgs.add(o3);
bookService.batchAdd(batchArgs);
}
(2)JdbcTemplate批量修改
// 批量修改
@Override
public void batchUpdate(List<Object[]> batchArgs) {
String sql = "update book set name=? , status=? where id=?" ;
int[] ints = jdbcTemplate.batchUpdate(sql,batchArgs) ;
System.out.println(Arrays.toString(ints));
}
測驗
@Test
public void Test() {
ApplicationContext context = new ClassPathXmlApplicationContext("cn\\pdsu\\jdbcTemplate\\xml\\bean1.xml") ;
BookService bookService = context.getBean("bookService" , BookService.class) ;
List<Object[]> batchArgs = new ArrayList<>() ;
Object[] o1 = {"JAVA","a",3};
Object[] o2 = {"C","b",4};
Object[] o3 = {"PYTHON","c",5};
batchArgs.add(o1);
batchArgs.add(o2);
batchArgs.add(o3);
bookService.batchUpdate(batchArgs);
}
(3)JdbcTemplate批量洗掉
@Override
public void batchDelete(List<Object[]> batchArgs) {
String sql = "delete from book where id=?" ;
int[] ints = jdbcTemplate.batchUpdate(sql,batchArgs) ;
System.out.println(Arrays.toString(ints));
}
測驗
@Test
public void Test() {
ApplicationContext context = new ClassPathXmlApplicationContext("cn\\pdsu\\jdbcTemplate\\xml\\bean1.xml") ;
BookService bookService = context.getBean("bookService" , BookService.class) ;
List<Object[]> batchArgs = new ArrayList<>() ;
Object[] o1 = {3};
Object[] o2 = {4};
batchArgs.add(o1);
batchArgs.add(o2);
bookService.batchDelete(batchArgs);
}
5.事務管理
1.事務操作(概念)
1.什么是事務
(1)事務是資料庫操作的基本單元,邏輯上的一組操作,要么都成功,有一個失敗就都失敗
(2)典型的場景:銀行轉賬
zhangsan轉賬100給lisi
zhangsan少100,lisi多100
2.事務的四大特性
(1)原子性(Atomicity):操作這些指令時,要么全部執行成功,要么全部不執行,只要其 中一個指令執行失敗,所有的指令都執行失敗,資料進行回滾,回到執行指令前的資料狀態,
(2)一致性(Consistency):事務的執行使資料從一個狀態轉換為另一個狀態,但是對于整個資料的完整性保持穩定,
(3)隔離性(Isolation):隔離性是當多個用戶并發訪問資料庫時,比如操作同一張表時,資料庫為每一個用戶開啟的事務,不能被其他事務的操作所干擾,多個并發事務之間要相互隔離,
(4)持久性(Durability):當事務正確完成后,它對于資料的改變是永久性的,
2.事務操作(搭建事務操作環境)

1.創建資料庫表,添加記錄


2.創建service,搭建dao,完成物件的創建和注入
service注入dao,在dao中注入JdbcTemplate,在JdbcTemplate中注入DataScurce
UserDao介面
public interface UserDao {
}
UserDaoImpl類
@Repository
public class UserDaoImpl implements UserDao{
@Autowired
private JdbcTemplate jdbcTemplate ;
}
UserService類
@Service
public class UserService {
@Autowired
private UserDao userDao;
}
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"
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">
<!-- 組件掃描 -->
<context:component-scan base-package="cn.edu.pdsu.work1"></context:component-scan>
<!-- 資料庫連接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close">
<property name="url" value="jdbc:mysql:///book_db" />
<property name="username" value="root" />
<property name="password" value="123456" />
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
</bean>
<!-- 創建JdbcTemplate物件 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 注入dataSource -->
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
3.在dao中創建兩個方法
多錢和少錢的方法,在service中創建轉賬的方法
UserDao
// 多錢
public void addMoney() ;
// 少錢
public void reduceMoney() ;
UserDaoImpl
// zhangsan轉賬100給lisi
// 多錢
@Override
public void addMoney() {
String sql = "update money set money=money+? where name=?" ;
jdbcTemplate.update(sql,100,"lisi") ;
}
// 少錢
@Override
public void reduceMoney() {
String sql = "update money set money=money-? where name=?" ;
jdbcTemplate.update(sql,100,"zhangsan") ;
}
測驗、結果
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml") ;
UserService userService = context.getBean("userService",UserService.class) ;
userService.accountMoney();
}

4.模擬例外
上面的代碼正常執行的情況下是沒有問題的,但是如果在代碼執行程序中出現了例外,則就會出現轉賬的問題
public void accountMoney() {
// 少錢
userDao.reduceMoney();
// 模擬例外
int i = 10 / 0 ;
// 多錢
userDao.addMoney();
}
將資料庫中的資料都還原到1000,再次模擬轉賬,結果如下


可以看到,例外出現后,zhangsan的錢確實少了,但是錢并沒有轉到lisi的賬戶下
(1)如何解決上面的問題?
使用事務
(2)事務操作程序

3.事務操作(spring事務管理介紹)
1.事務添加到javaee三層結構的Service層(業務邏輯層)
2.在Spring中進行事務管理操作
兩種方式:編程式事務管理和宣告式事務管理(使用)
3.宣告式事務管理
(1)基于注解(使用)
(2)基于xml組態檔
4.在spring中進行宣告式事務管理,底層使用AOP原理
5.spring事務管理API
提供的介面,代表事務管理器,這個介面針對不同的框架提供了不同的實作類

4.事務操作(基于注解方式進行事務管理)
1.在spring的組態檔中創建事務管理器
<!-- 創建事務管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入資料源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
2.在spring組態檔中開啟事務注解
(1)在spring組態檔中引入tx名稱空間
<?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">
(2)開啟事務的注解
<!-- 開啟事務的注解 -->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
3.在service類上或service類中的方法上添加事務的注解
(1)@Transactional,這個注解既可以添加到類上面,也可以添加到方法上面
(2)添加到類上面表示類中的所有方法都添加了事務
(3)添加到方法上面表示只一個方法添加了事務

4.測驗、結果
代碼執行前表中資料

執行代碼

代碼執行后表中資料

5.事務操作(宣告式事務管理引數配置)
1.注解@Transactional
在service類上面添加注解@Transactional,在這個注解中可以配置事務相關引數
(1)propagation:事務的傳播行為
多事務方法之間進行呼叫,這個程序中事務是如何進行管理的

(2)isolation:事務的隔離級別
1.事務里面有一個特性,多事務操作之間不會互相影響,不考慮隔離性會產生很多問題
2.三個問題:臟讀、不可重復讀、虛(幻)讀
臟讀:一個未提交事務讀取到另外一個未提交事務的資料
不可重復讀:一個未提交的事務讀取到另外一個提交事務修改的資料
幻讀:一個未提交事務讀取到另外一個提交事務的資料
(3)通過事務的隔離級別來解決問題


(3)timeout:超時時間
事務需要在一定的時間內進行提交,否則將進行回滾,默認情況下其值為-1,也就是沒有設定超時時間,設定時間以秒為單位進行計算
(4)readOnly:是否只讀
1.讀:查詢操作 寫:增刪改操作
2.readOnly的默認值是false,表示增刪改查都可以進行操作
3.設定readOnly的值為true后只能進行查詢
(5)rollbackFor:回滾
設定出現了哪些例外進行回滾
(6)noRollbackFor:不會滾
設定出現了哪些例外不進行回滾
6.事務操作(xml宣告式事務管理)
1.在spring組態檔中進行配置
(1)第一步配置事務管理器
(2)第二步配置通知
(3)第三步配置切入點和切面
<!-- 1.配置事務管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入資料源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 2.配置通知 -->
<tx:advice id="txAdvice">
<!-- 配置事務引數 -->
<tx:attributes>
<!-- 指定哪種規則的方法上添加事務 -->
<tx:method name="accountMoney" propagation="REQUIRED"/> <!-- 表示在accountMoney方法上添加事務 -->
<tx:method name="account*"/> <!-- 表示在以account開頭的方法上添加事務 -->
</tx:attributes>
</tx:advice>
<!-- 3.配置切入點和切面 -->
<aop:config>
<!-- 配置切入點 -->
<aop:pointcut id="p" expression="execution(* cn.edu.pdsu.work1.service.UserService.*(..))"/>
<!-- 配置切面 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="p"></aop:advisor>
</aop:config>
7.事務操作(完全注解開發)
1.創建配置類代替xml組態檔
Config配置類
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
@Configuration // 宣告配置類
@ComponentScan(basePackages = "cn.edu.pdsu.work1") // 組件掃描
@EnableTransactionManagement // 開啟事務
public class Config {
// 創建資料庫的連接池
@Bean
public DruidDataSource getDruidDataSource() {
DruidDataSource druidDataSource = new DruidDataSource() ;
druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
druidDataSource.setUrl("jdbc:mysql:///book_db");
druidDataSource.setUsername("root");
druidDataSource.setPassword("123456");
return druidDataSource ;
}
// 創建Jdbc模板物件
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
// 到ioc容器中根據型別找到dataSource
JdbcTemplate jdbcTemplate = new JdbcTemplate() ;
// 注入dataSource
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate ;
}
// 創建事務管理器
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager() ;
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
測驗,結果
@Test
public void test2() {
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class) ;
UserService userService = context.getBean("userService",UserService.class) ;
userService.accountMoney();
}
測驗前資料庫資料

執行代碼

測驗后資料庫資料

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/276175.html
標籤:java
上一篇:Java 面向物件——封裝
