Spring 入门,包含可编译的代码,详细讲解IOC及AOP,内含有面试题

一榔捶

Spring

Spring框架概述

1、Spring是轻量级的开源的JavaEE框架
2、Spring可以解决企业应用开发的复杂性
3、Spring有两个核心组成部分:IOC和AOP
(1)、IOC:控制反转,把创建对象过程交给Spring进行管理降低耦合度

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

(2)、AOP:面向切面,不修改源代码进行功能增强
4、Spring 特点
(1)、方便解耦,简化开发
(2)、Aop 编程支持
(3)、方便程序测试
(4)、方便和其他框架进行整合
(5)、方便进行事务操作
(6)、降低 API 开发难度
5、代码块的编写

创建普通方法–创建Spring配置文件,在配置文件配置创建的对象XML-config…Spring.xml----测试代码编写:加载Spring配置文件(ApplicationContext)

public class User{
  public void add(){
    System.out.println("add.....")
  }
}
<?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">
<!--        第一种方法:-->
        <bean id="user" class="day1.User"></bean>
public class User {
    public void add(){
        System.out.println("add........");
    }
}
@Test
    public void testAdd1() {
        ApplicationContext context = new	  ClassPathXmlApplicationContext("bean1.xml");
        User user = context.getBean("user", User.class);
        System.out.println(user);
        user.add();
    }
6、IOC思想
1、IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
2、Spring提供IOC容器实现两种方式:(两个接口)

​ (1)、BeanFactory:IOC容器的基本实现,是Spring的内部借口,加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象

​ (2)、ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,由开发人员使用,加载配置文件时候就已经把配置文件的对象进行创建了。

3、IOC操作Bean管理

​ (0)、Bean管理指的是两个操作

​ (1)、Spring创建对象

​ (2)、Spring注入属性

4、Bean管理操作有两种方式

​ (1)、基于xml配置文件方法实现

​ (2)、基于注解方式实现

使用set方法进行注入
public class Book {
    private String bName;
    private String bauthor;
    public void setbName(String bName) {
        this.bName = bName;
    }
    public void setBauthor(String bauthor){
        this.bauthor = bauthor;
    }
    
    public void testDemo(){
        System.out.println(bName+"::::::"+bauthor);
    }
}
 @Test
    public void testBook(){
       ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        Book book = context.getBean("book", Book.class);
        System.out.println(book);
        book.testDemo();
    }
<bean id="book" class="day1.Book">
<!--        使用property完成属性注入        -->
                <property name="bName" value="易筋经"></property>
                <property name="bauthor" value="达摩老祖"></property>
        </bean>
使用有参构造进行注入(constructor-arg)
public class Orders {
    private String oName;
    private String address;
    //有参数构造
    public Orders(String oName,String address){
        this.oName=oName;
        this.address=address;
    }
    public void orderTest(){
        System.out.println(oName+":::::"+address);
    }
}
<bean id="orders" class="day1.Orders">
                <constructor-arg name="oName" value="啦啦啦"></constructor-arg>
                <constructor-arg name="address" value="China"></constructor-arg>
        </bean>
 @Test
    public void testOrders(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        Orders orders = context.getBean("orders", Orders.class);
        System.out.println(orders);
        orders.orderTest();
    }
7、IOC操作Bean管理
1、xml注入其他类型的属性

(1)、null值:

<property name="address">
                        <null/>
                </property>

(2)、属性中包含特殊符号,例如:<>

<property name="address">
                       <value>
                               <![CDATA[<<南京>>]]>
                       </value>
                </property>
2、注入属性-外部的bean

(1)、创建两个类service类和dao类

public class UserService {

    private UserDao userDao;
    public void setUserDao(UserDao userDao){
        this.userDao = userDao;
    }
    public void add(){
        System.out.println("service add.......");
        userDao.update();
    }
}
public interface UserDao {
    public void update();
}
public class UserDaoImpl implements UserDao {

    @Override
    public void update() {
        System.out.println("dao update ............");
    }
}

(2)、service中调用dao方法

private UserDao userDao;

(3)、在springxml文件中进行配置(利用ref放入property中)

<!--    外部bean的注入:::::::::::-->
    <bean id="userService" class="day2.service.UserService">
<!--        注入userDao对象
            name属性:类里面属性名称
            ref属性:创建userDao对象bean标签id值
            使用ref让一个Bean作为另一个Bean的成员变量(属性)
-->
       <property name="userDao" ref="userDaoImpl"></property>
    </bean>
    <bean id="userDaoImpl" class="day2.dao.UserDaoImpl"></bean>
3、注入属性-内部的bean

(1)、一对多关系:部门(Dept)和员工(Emp),一个部门有多个员工,一个员工属于一个部门

(2)、在实体类之间表示一对多关系,员工表示所属部门,使用对象类型进行表示

public class Dept {
    private String dName;

    public void setdName(String dName) {
        this.dName = dName;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "dName='" + dName + '\'' +
                '}';
    }
}
public class Emp {
    private String eName;
    private String gender;
    private Dept dept;

    public Dept getDept() {
        return dept;
    }

    public void seteName(String eName) {
        this.eName = eName;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }
    public void add(){
        System.out.println(eName+"::::"+gender+"::::"+dept.toString());
    }
}
<bean id="emp" class="day2.bean.Emp">
<!--        设置两个普通属性-->
        <property name="eName" value="lucy"></property>
        <property name="gender" value="女"></property>
<!--        设置对象类型属性-->
        <property name="dept">
            <bean id="dept" class="day2.bean.Dept">
                <property name="dName" value="安保"></property>
            </bean>
        </property>
    </bean>

tips:使用内嵌方法进行SpringXml文件的配置

4、注入属性-级联赋值
<!--级联赋值-->
    <bean id="emp" class="day2.bean.Emp">
        <property name="eName" value="123"></property>
        <property name="gender" value="女"></property>
        <property name="dept" ref="dept"></property>
        <property name="dept.dName" value="大哥"></property><!-- 需要get方法  -->
    </bean>
    <bean id="dept" class="day2.bean.Dept">
<!--        <property name="dName" value="财务"></property>-->
    </bean>

其中,第二种方法中的"dept.dName"需要Emp中的dept类的属性的get方法

5、注入属性-集合、数组、列表属性

创建类、定义数组、list、map、set类型属性,生成对应的set方法

public class collectionType {
    //数组类型属性
    private String[] courses;
    //list集合类型属性
    private List<String> list;
    //map集合型属性
    private Map<String,String> map;
    //set属性
    private Set<String> sets;
    //学生学的多门课程
    private List<course> courseList;
    public void setCourseList(List<course> courseList){
        this.courseList = courseList;
    }
    public void setSets(Set<String> sets) {
        this.sets = sets;
    }
    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 add(){   System.out.println(Arrays.toString(courses)+":::"+list+":::"+map+":::"+sets);
        System.out.println(courseList);
    }
}
public class course {
    private String cName;
    public void setcName(String cName) {
        this.cName = cName;
    }
    @Override
    public String toString() {
        return "course{" +
                "cName='" + cName + '\'' +
                '}';
    }
}
    <bean id="collect" class="day3.collectionType">
        <property name="courses">
            <array>
                <value>123414</value>
                <value>12421441251</value>
            </array>
        </property>
        <property name="list">
            <list>
                <value>zhangyulong</value>
                <value>renwangba</value>
            </list>
        </property>
        <property name="map">
            <map>
                <entry key="123" value="456"></entry>
            </map>
        </property>
        <property name="sets">
            <set>
                <value>Mysql</value>
                <value>Redis</value>
            </set>
        </property>
     

当注入的值为对象时,xml文件配置如下:

<!--注入list集合类型,值是对象-->
        <property name="courseList">
            <list>
                <ref bean="course1"></ref>
                <ref bean="course2"></ref>
            </list>
        </property>

    </bean>
    <bean id="course1" class="day3.course">
        <property name="cName" value="nande"></property>
    </bean>
    <bean id="course2" class="day3.course">
        <property name="cName" value="nvde"></property>
    </bean>
6、提取集合注入部分

将xmlns:schemaLocation中的beans改为util(复制后),然后借助ref进行提取使用

<?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/util"
       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">
        <util:list id="bookList">
            <value>lalala</value>
            <value>hahaha</value>
            <value>houhouhou</value>
        </util:list>
    <bean id="book" class="day3.Book">
        <property name="list" ref="bookList"></property>
    </bean>
</beans>
7、工厂FactoryBean

1、Spring类型分为两种bean,一种是普通bean,另一种是工厂bean(FactoryBean)

普通bean:在配置文件中定义bean类型就是返回类型

工厂bean:在配置文件中定义bean类型可以和返回类型不一样

第一步:创建类,让这个类作为工厂bean,实现接口FactoryBean

第二部:实现接口里面的方法,在实现的方法中定义返回的bean类型

public class MyBean implements FactoryBean<course> {

    @Override
    public course getObject() throws Exception {
        course cours = new course();
        cours.setcName("abc");
        return cours;
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}
    <bean id="myBean" class="day3.factoryBean.MyBean">
    </bean>
    @Test
    public void test3(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean7.xml");
        course course = context.getBean("myBean", course.class);
        System.out.println(course);
    }
8、bean作用域(单实例和多实例)关键词:scope=“prototype”

1、在Spring里,设置创建bean实例是单实例还是多实例

2、在Spring里,默认情况下是单实例

public class Book {
    private List<String> list;
    public void setList(List<String> list){
        this.list = list;
    }
    public void add(){
        System.out.println(list);
    }
}
    @Test
    public void test2(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean6.xml");
        Book book1 = context.getBean("book", Book.class);
        Book book2= context.getBean("book",Book.class);
        System.out.println(book1);
        System.out.println(book2);
        book1.add();
        book2.add();
    }
<util:list id="bookList">
            <value>lalala</value>
            <value>hahaha</value>
            <value>houhouhou</value>
        </util:list>
<bean id="book" class="day3.Book" scope="prototype">
        <property name="list" ref="bookList"></property>
    </bean>
8、bean的生命周期
1、生命周期概念

(1)、从对象创建到对象销毁的过程

2、bean生命周期

(1)、通过构造器创建bean实例(无参数构造)

(2)、声明一个私有属性,为bean的属性设置值(调用set方法)

(3)、调用bean的初始化方法(xml文件中进行配置)(init-method=“ ”)

(4)、bean可以使用

(5)、调用销毁方法(同样需要进行xml文件配置)(destory-method=“ ”)

3、演示bean生命周期
public class Orders {
    public Orders(){
        System.out.println("1、执行无参构造创建bena实例");
    }
    private String oneName;
    public void setOneName(String oneName){
        System.out.println("2、调用set方法设置属性");
        this.oneName = oneName;
    }
    public void initMethod(){

        System.out.println("4、执行初始化方法");
    }
    public void destoryMethod(){
        System.out.println("7、执行销毁方法");
    }
}
<bean id="orders" class="day4.Orders" init-method="initMethod" destroy-method="destoryMethod">
        <property name="oneName" value="张大帅"></property>
    </bean>
  //后置处理器
    <bean id="myBeanPost" class="day4.MyBeanPost"></bean>
 @Test
    public void testOrders(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean8.xml");
        Orders orders = context.getBean("orders", Orders.class);
        System.out.println("6、获取创建的bean实例对象");
        System.out.println(orders);
        orders.destoryMethod();
    }

添加后置处理器

public class MyBeanPost implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("3、初始化之前执行的方法");
        return null;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("5、初始化之后执行的方法");
        return null;
    }
}
1、执行无参构造创建bena实例
2、调用set方法设置属性
3、初始化之前执行的方法
4、执行初始化方法
5、初始化之后执行的方法
6、获取创建的bean实例对象
day4.Orders@4e718207
7、执行销毁方法
9、xml自动装配
1、什么是自动装配

(1)、根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值注入

2、演示自动装配过程

(1)、根据属性名称自动注入

bean标签中 autowire进行自动装配

autowire=“byName”:根据属性名称注入,注入值bean的id值和类属性名称一样

Autowire=“byType”:根据属性类型一样

10、引入外部属性文件(Druid连接)
1、直接配置数据库信息

(1)、配置Druid连接池

(2)、引入Druid连接池依赖jar包

       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">

<!--    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">-->
<!--        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>-->
<!--        <property name="url" value="jdbc:mysql://localhost:3306/book?characterEncoding=utf8"></property>-->
<!--        <property name="username" value="root"></property>-->
<!--        <property name="password" value="374761727"></property>-->
<!--    </bean>-->

<!--    引入外部属性文件-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
<!--    配置连接池-->
    <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>

Tips:其中context需要进行修改,xmlns:context以及xsi:schemaLocation

创建外部文件:jdbc.properties

prop.driverClass=com.mysql.cj.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/book?characterEncoding=utf8
prop.userName=root
prop.Password=374761727
11、基于注解方式进行Bean管理
1、什么是注解

(1)、注解是代码特殊标记,格式:@注解名称(属性名称=属性值)

(2)、使用注解,注解作用在类上面,方法上面,属性上面

(3)、使用注解目的:简化xml配置

2、Spring针对Bean管理中创建对象提供注解

(1)、@Component:普通组件

(2)、@Service:业务层组件

(3)、@Controller:控制层组件

(4)、@Repository:持久层组件

tips:以上四种注解可在任意功能时进行使用,都可以用来创建bean实例

3、基于注解方式实现对象的创建

(1)、引入依赖

Spring-aop-5.2.6.RELEASE.jar

(2)、开启组件扫描**(如果是多个包,使用逗号隔开)**

    <context:component-scan base-package="day4">
    </context:component-scan>

(3)、创建类,并在类的上方添加创建对象的注解

@Service//<bean id="userService" class="..">
public class UserService {

@Autowired//需要为UserDaoImpl实现类中也加入注解@实现对象创造
private UserDao userDao;

    public void add(){
        System.out.println("add........");
        userDao.add();
    }
}

(4)、开启组件扫描细节配置(filter为过滤器,include-filter设置扫描哪些内容)

<context:component-scan base-package="com.atguigu" use-default-
filters="false">
 <context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

(5)、基于注解方式实现属性注入

第一步:创建service和dao对象,在两个类中添加对象注解

第二步:在service中注入dao对象,在service类中添加dao的类型属性

@Autowired:根据属性类型进行自动装配

@Qualifier:根据名称进行引入,需要和@Autowired一起使用,并借用value

@Resource:可以根据类型注入,也可以根据名称注入,属于注解包不属于Spring包

@Value:注入普通类型属性

@Service//<bean id="userService" class="..">
public class UserService {

@Autowired//需要为UserDaoImpl实现类中也加入注解@实现对象创造
private UserDao userDao;

    public void add(){
        System.out.println("add........");
        userDao.add();
    }
}
public interface UserDao {
    public void add();
}
@Repository(value = "userDaoImpl1")
public class UserDaoImpl implements UserDao {

    @Override
    public void add() {
        System.out.println("Dao add........");
    }
}
@Test
    public void testUserService(){
        //采用注解的方式
        ApplicationContext context = new ClassPathXmlApplicationContext("bean10anno@.xml");
        //查找目录下所有带@四项的注解
        UserService userService = context.getBean("userService", UserService.class);
        System.out.println(userService);
        userService.add();
    }
       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="day4">
    </context:component-scan>
12、完全配置开发(完全使用注解方式)

1、创建配置类,取代xml文件,@Configuration@ComponentScan(basePackages={" "})

@Configuration
@ComponentScan(basePackages={"day4"})
public class SpringConfig {

}

2、编写测试类

    @Test
    public void testUserservice(){
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService userService = context.getBean("userService", UserService.class);
        System.out.println(userService);
        userService.add();
    }

第二部分:AOP

1、什么是AOP

(1)、面向切面编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使业务中各业务之间的逻辑之间的耦合度降低,提高程序可用性,并提高开发的效率

(2)、通俗描述:不通过修改源代码的方式,在主干功能中添加新功能

2、JDK动态代理
1、使用JDK动态代理,使用Proxy类里面的方法创建代理对象

(1)、调用newProxyInstance方法

在这里插入图片描述

方法中有三个参数:

第一参数:类加载器-当前类的:Proxy

第二参数:增强方法所在的类(Dao),这个类实现的接口(Impl),支持多个接口

第三参数:实现这个接口InvocationHandler,创建代理对象,写增强的那部分代码

(2)、编写JDK动态代理代码

创建接口,定义方法

public interface UserDao {
    public int add(int a,int b);
    public String update(String id);
}

创建接口实现类,实现方法

public class UserDaoImpl implements UserDao {
    @Override
    public int add(int a, int b) {
        return a+b;
    }

    @Override
    public String update(String id) {
        return id;
    }
}

使用Proxy类创建接口代理对象(程序的入口)

public class JDkProxy {
    public static void main(String[] args) {

        Class[] interfaces = {UserDao.class};
        UserDaoImpl userDaoImpl = new UserDaoImpl();
        UserDao userDao = (UserDao) Proxy.newProxyInstance(JDkProxy.class.getClassLoader(),//1
                interfaces, new UserDaoProxy(userDaoImpl));
        int result = userDao.add(8, 9);
        System.out.println(result);
    }
}

UserDaoProxy对象

public class UserDaoProxy implements InvocationHandler {
    private Object obj;//UserDaoImpl的arg,由1到此处
    public UserDaoProxy(Object obj) {
        this.obj=obj;
    }

    @Override
    public Object invoke(Object o, Method method, Object[] args) throws Throwable {
        System.out.println("方法完成前:"+method.getName()+ Arrays.toString(args));
        Object invoke = method.invoke(obj, args);
        System.out.println("behiend:"+obj);
        return invoke;
    }
}

3、AOP的术语及常用说法
1、连接点

概念:类中那些方法可以被增强,称为连接点。(基本所有的类都可以作为连接点)

2、切入点

概念:实际真正的被增强的方法被叫做切入点

3、通知(增强)

概念:实际增强的方法的逻辑的部分称为通知(增强)

通知具有多种类型:

  • 前置通知(@Before)
  • 后置通知 (@AfterReturning)
  • 环绕通知(@Around)
  • 异常通知(@AfterThrowing)
  • 最终通知(@After)
4、切面

概念:把通知应用到切入点的过程,即将增强的方法应用到被增强的方法中

4、AOP操作(准备工作)
1、Spring框架一般基于 AspectJ 实现AOP操作

AspectJ 不是Spring组成部分,它独立于AOP框架,一般把AspectJ 和 Spring框架一起使用,进行AOP操作

2、基于AspectJ实现AOP操作

两种方法:基于xml以及基于注解,通常情况下我们使用基于注解的方法实现

3、引入依赖

spring-aspects-5.2.6.RELEASE.jar

以及Springsource三个jar包

4、切入点的表达式
  • 可以知道对哪个类中的哪个方法进行增强
  • 语法结构:execution([权限修饰符] [返回类型] [类全路径] 方法名称 )

例如:execution( day5.AopAnno.Proxy.User.add(…))*

5、AOP操作(具体步骤)
1、创建类,在类中定义一个add()方法
//被增强的类
@Component
public class User {
    public void add(){
        System.out.println("add........");
    }
}
2、增强的类的方法UserProxy**(两个类中均实现注解,即@Component那四个注解)**
//增强的类的方法
@Component
@Aspect
public class UserProxy {

    @Before(value = "execution(* day5.AopAnno.Proxy.User.add(..))")
    public void before(){
        System.out.println("before......");
    }
    @AfterReturning(value = "execution(* day5.AopAnno.Proxy.User.add(..))")
    public void afterReturning(){
        System.out.println("afterReturning....");
    }
    @After(value = "execution(* day5.AopAnno.Proxy.User.add(..))")
    public void after(){
        System.out.println("After.....");
    }
    @AfterThrowing(value = "execution(* day5.AopAnno.Proxy.User.add(..))")
    public void afterThrowing(){
        System.out.println("AfterThrowing.....");
    }
    @Around(value = "execution(* day5.AopAnno.Proxy.User.add(..))")
    public void arround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        System.out.println("Around....环绕之前");
        proceedingJoinPoint.proceed();
        System.out.println("Around....环绕之后");
    }
}
3、开启注解扫描,在Spring配置文件中,其中@Aspect在增强类上实现
<context:component-scan base-package="day5.AopAnno">
    </context:component-scan>
    <!--开启Aspect生成代理对象-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
4、相同的切入点抽取
@Pointcut(value = "execution(* day5.AopAnno.Proxy.User.add(..))")
public void pointdemo(){
}
5、有多个增强类对同一个方法进行增强,设置增强类优先级

在增强类上面添加注解

@Order(数字类型值),数字类型值越小优先级越高

第三部分:JdbcTemplate

1、什么是JdbcTemplate
1、Spring框架对JDBC进行封装,使用JdbcTemplate方便实现对数据库进行操作
2、准备工作
(1)、引入相关jar包

在这里插入图片描述

Spring-jdbc-5.2.6.RELEASE.jar、Spring-orm-5.2.6.RELEASE.jar、Spring-tx-5.2.6.RELEASE.jar

(2)、在Spring配置文件中配置数据库连接池
<!--    引入外部属性文件-->
<!--    <context:property-placeholder location="classpath:jdbc.properties"/>-->
<!--    配置连接池-->
    <context:component-scan base-package="day6NoFinal"></context:component-scan>
    <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>
      <!--配置JdbcTemplate对象,注入DataSource-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

jdbc.properties如下

prop.driverClass=com.mysql.cj.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/book?characterEncoding=utf8
prop.userName=root
prop.Password=374761727
(3)、创建Book、Service、Dao、Impl类并在dao中注入jdbcTemplate对象
public class Book {
    private String userId;
    private String username;
    private String ustatue;
    public void setUserId(String userId) {
        this.userId = userId;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public void setUstatue(String ustatue) {
        this.ustatue = ustatue;
    }
    public String getUserId() {
        return userId;
    }
    public String getUsername() {
        return username;
    }
    public String getUstatue() {
        return ustatue;
    }
}
@Service
public class BookService {
    @Autowired
    private BookDao bookDao;

    public void addBook(Book book){
        bookDao.add(book);
    }
    public void updateBook(Book book){
        bookDao.update(book);
    }
    public void deleteBook(Book book){
        bookDao.delete(book);
    }
}
@Repository
public interface BookDao {
    public void add(Book book);
    void update(Book book);
    void delete(Book book);
}
3、JdbcTemplate操作数据库
@Repository
public class BookDaoImpl implements BookDao {
//注入JdbcTemplate
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Override
    public void add(Book book) {
        String sql = "insert into t_book1 values(?,?,?)";
        int update = jdbcTemplate.update(sql,book.getUserId(), book.getUsername(), book.getUstatue());
        System.out.println(update);
    }
    @Override
    public void update(Book book) {
        String sql = "update t_book1 set username=?,ustatue=? where userId=?";
        int update = jdbcTemplate.update(sql, book.getUsername(), book.getUstatue(), book.getUserId());
        System.out.println(update);
    }
    @Override
    public void delete(Book book) {
        String sql = "delete from t_book1 where userId = ?";
        int update = jdbcTemplate.update(sql, book.getUserId());
        System.out.println(update);
    }
}
测试类
public class testJdbcTemplate {
    @Test
    public void test(){
        ApplicationContext context =
                new ClassPathXmlApplicationContext("bean12.xml");
        BookService bookService = context.getBean("bookService", BookService.class);
        Book book = new Book();
        book.setUserId("1");
        book.setUsername("142");
        book.setUstatue("sfsa");
        bookService.addBook(book);
    }
    @Test
    public void tes1(){
        ApplicationContext context =
                new ClassPathXmlApplicationContext("bean12.xml");
        BookService bookService = context.getBean("bookService", BookService.class);
        Book book = new Book();
        book.setUserId("1");
        book.setUsername("111111");
        book.setUstatue("2222222");
        bookService.addBook(book);
    }
    @Test
    public void test2(){
        ApplicationContext context =
                new ClassPathXmlApplicationContext("bean12.xml");
        BookService bookService = context.getBean("bookService", BookService.class);
        Book book = new Book();
        book.setUserId("1");
        bookService.deleteBook(book);
    }

}
jdbcTemplate操作数据库(查询返回某个值)
@Override
public int selectCount() {
	String sql = "select count(*) from t_book";
	Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
return count;
}
jdbcTemplate操作数据库(查询返回对象)

其中RowMapper是接口,针对返回不同类型的数据,使用这个接口里面的实现类完成数据封装,其中使用到了匿名实现类

@Override
public Book findBookInfo(String id) {
	String sql = "select * from t_book where user_id=?"; //调用方法
	Book book = jdbcTemplate.queryForObject(sql, new
	BeanPropertyRowMapper<Book>(Book.class), id); 
return book;
}
jdbcTemplate操作数据库(查询返回集合)
public List<Book> findAllBook() {
	String sql = "select * from t_book";
//调用方法
	List<Book> bookList = jdbcTemplate.query(sql, new
	BeanPropertyRowMapper<Book>(Book.class)); 
return bookList;
}

第四部分:事务

1、什么是事务
(1)、基本操作

事务是数据库操作最基本单元,绑定于上一组操作,要么都成功,要么都失败,一荣俱荣,一损俱损。

(2)、典型场景

银行转账:

  • lucy转账100元给mary
  • lucy少100,mary多100元
(3)、事务四个特性(ACID)
  • 原子性
  • 一致性
  • 隔离性
  • 持久性
(4)、事务操作(搭建事务操作环境)
2、创建数据库表t_book,添加记录

在这里插入图片描述

useridusernamemoney
1lucy1000
2mary1000
3、创建service,搭建dao,完成对象创建和注入关系
(1)service注入dao,在到注入JdbcTemplate,在JdbcTemplate注入DataSource
@Service
@Transactional
public class UserService {
    @Autowired
    private UserDao userDao;
    public void accountMoney(){
        userDao.addMoney();
        //模拟错误
//        int i = 10/0;
        userDao.reduceMoney();
    }
}
public interface UserDao {
    public void addMoney();
    public void reduceMoney();
}

实现两个方法,多钱和少钱的方法,并在service中创建方法(转账:见代码1)

@Repository
public class UserDaoImpl implements UserDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Override
    public void reduceMoney() {
        String sql = "update t_account set money=money-? where username=?";
        jdbcTemplate.update(sql,100,"lucy");
    }
    @Override
    public void addMoney() {
        String sql = "update t_account set money=money+? where username=?";
        jdbcTemplate.update(sql,100,"mary");
    }
}

模拟错误后,第一条命令执行,第二条命令由于错误并未执行,故此我们引入事务的概念

4、事务操作
1、事务添加到JavaEE三层结构里面Service层(业务逻辑层)
2、在Spring进行事务管理操作

(1)、有两种方式:编程试事务管理和声明式事务管理(使用)

3、声明式事务管理方式

(1)、基于注解方式

(2)、基于xml配置文件方式

4、在Spring中进行声明式事务管理,底层使用AOP原理
5、Spring事务管理API

(1)、提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类

5、基于声明式事务管理
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">


    <!--    引入外部属性文件-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <!--    配置连接池-->
    <context:component-scan base-package="day7"></context:component-scan>
    <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>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
<!--    开启事务的注解,并指定名字为transactionManager-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

</beans>

(2)、开启事务注解

<!--    开启事务的注解,并指定名字为transactionManager-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
3、在service类上面(或者service类里面方法上面)添加事务注解

(1)、@Transactional,这个注解添加到类上面,也可以添加方法上面

(2)、如果把这个注解添加到类上面,这个类里面所有的方法都添加事务

(3)、如果把这个注解添加方法上面,为这个方法添加事务

4、事务操作(声明式事务管理参数配置‘六项’)
(1)、propagation:事务传播行为

概念:多事务方法直接进行调用,这个过程中事务是如何进行管理的

形式:@Transactional(propagation = Propagation.REQUIRED)

例如:有两个类add()、和update(),其中add()加入事务注解@Transactional

  • REQUIRED

    如果add方法本身有事务,调用update方法之后,update使用当前add方法里面的事务,如果add方法本身没有事务,则调用update方法后,创建新事务

  • REQUIRED_NEW

    使用add()方法调用update()方法,无论add()方法是否有事务,都创建新事务

  • SUPPORTS

    如果有事务在运行中,当前的方法就在这个事务内运行,否则不可运行在事务中

  • NOT_SUPPORTE

  • MANDATPORY

  • NEVER

  • NESTED

(2)、isolation:事务隔离级别

概念:事务有特性称为隔离性,多事务操作之间不会产生影响,不考虑隔离性回产生很多问题:如下

  • 脏读:一个未提交的事务读取到了另一个未提交事务但已修改数值的数据(回滚了)

    在这里插入图片描述

    由于事务回滚,并未提交的数据60000被东方不败所提取到

  • 不可重复读:一个未提交事务读取到另一提交事务修改的数据

    在这里插入图片描述

    在东方不败未提交事务的时候,岳不群已经提交了事务,导致东方不败再一次获取到了岳不群事务提交后修改的数据

  • 幻读:一个未提交事务读取到另一提交事务所添加的数据(与上同理)

解决:通过设置事务隔离级别,解决问题

在这里插入图片描述

形式为:@Transactional(isolation = Isolation.REPERTABLE_READ)

(3)timeout:超时时间

(1)事务需要在一定时间内进行提交,如果不提交进行回滚

(2)默认值是 -1 ,设置时间以秒单位进行计算

(4)readOnly:是否只读

(1)读:查询操作,写:添加修改删除操作
(2)readOnly 默认值 false,表示可以查询,可以添加修改删除操作

(3)设置 readOnly 值是 true,设置成 true 之后,只能查询

(5)rollbackFor:回滚

(1)设置出现哪些异常进行事务回滚

(6)noRollbackFor:不回滚

(1)设置出现哪些异常不进行事务回滚

第五部分:Spring5新特性

留待SpringMVC后进行分解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值