spring框架学习笔记

spring框架

一、框架

1、框架是一个半成品

封装好了一些代码,不需要你写了,你直接可以使用。

2、框架是一种开发规范

每个人都有自己的开发习惯,但是我们进行团队开发,需要统一开发规范。

3、框架可以提高开发效率

项目的结构和基础都由框架提供,我们直接编写业务需求。

4、解耦

二、spring框架

1、spring是Java开发的核心框架

每个公司都会用。

springboot是spring框架的简化框架。

2、spring是全方位的JavaEE解决方案。

spring框架提供了JavaEe开发所需要的所有东西。

Spring框架模块

3、spring全家桶

spring核心框架,springMVC,spring Data,spring security,spring boot,springCloud==

4、spring框架的核心功能

IOC:bean工厂,spring容器。

AOP:面向切面编程(底层使用动态代理)。

spring jdbc:连接关系型数据库。

事务管理:aop的体现。

整合其他框架。

5、spring有两种配置形式

xml形式

注解

三、项目中导入spring框架

1、至少需要如下jar包

spring-core

spring-context

spring-beans

spring-aop(如果不使用注解,可以不引入)

spring-expressEl

logging

这是核心包,使用spring框架必须引入的包。

如果你要使用spring的其他功能,在此基础上引入相应的jar包。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vrL6VlPM-1632315227620)(spring框架.assets/image-20210915171326224.png)]

2、创建spring配置文件

src/main/resources: 配置文件名随便起,一般喜欢叫applicationContext.xml

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8oEcQkwn-1632315227622)(spring框架.assets/image-20210915171620078.png)]

四、控制反转IOC

1、控制反转

创建对象的权力交给spring容器。

由spring容器帮助我们创建好对象,然后将对象存在spring容器中管理。

如果我们想要使用这些对象,直接从spring容器中获取对象。

controller、service、dao一般都放入spring容器中,实体类和工具类一般不放。

2、编写一个类

package com.hs;

public class User {
    private   int  id;
    private  String  name;
    private   String  username;
    private  String  passwd;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPasswd() {
        return passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }
}

3、配置bean

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


    <!--将com.hs.User交给spring容器创建和管理-->
    <!--默认bean对象是单例的-->
    <!--id和name作用相同,一般使用id-->
    <!--class是要实例化的类,包名.类名-->
    <bean   id="u1"   name="u1"  class="com.hs.User"></bean>

</beans>

4、获取对象

从spring容器中获取对象。

获取对象的方式:

(1)BeanFactory

(2)ApplicationContext:ClasspathXmlApplicationContext(推荐)

(3)ApplicationContext:FileSystemXmlApplicationContext

package com.hs;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
//        1、初始化容器
//        2、读取applicationContext.xml
//        3、创建bean
        ApplicationContext  context=new ClassPathXmlApplicationContext("classpath:applicationContext.xml");


//        获取bean(默认是单例的)
        User u1 = (User)context.getBean("u1");
        User u2 = (User)context.getBean("u1");

        System.out.println(u1.getId());
        System.out.println(u1==u2);   //true
    }
}

五、依赖注入DI

1、依赖注入

a对象依赖了b对象,那么spring容器可以将b对象赋给a对象的属性。

2、注入的前提条件

a对象和b对象必须由spring容器创建和管理。

3、案例

package com.hs;

public class User {
    private   int  id;
    private  String  name;
    private   String  username;
    private  String  passwd;
//    依赖注入
    private  Company   company;

    public Company getCompany() {
        return company;
    }

    public void setCompany(Company company) {
        this.company = company;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPasswd() {
        return passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }
}
package com.hs;

public class Company {
    private  int  cid;
    private  int  cname;

    public int getCid() {
        return cid;
    }

    public void setCid(int cid) {
        this.cid = cid;
    }

    public int getCname() {
        return cname;
    }

    public void setCname(int cname) {
        this.cname = cname;
    }
}
<?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">


    <!--将com.hs.User交给spring容器创建和管理-->
    <!--默认bean对象是单例的-->
    <!--id和name作用相同,一般使用id-->
    <!--class是要实例化的类,包名.类名-->
    <!--property:ref   注入指定id的对象  -->
    <bean   id="u1"   name="u1"  class="com.hs.User">
        <property name="company" ref="cm"></property>
    </bean>

    <bean  id="cm"   class="com.hs.Company"></bean>

</beans>
package com.hs;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
//        1、初始化容器
//        2、读取applicationContext.xml
//        3、创建bean
        ApplicationContext  context=new ClassPathXmlApplicationContext("classpath:applicationContext.xml");


//        获取bean
        User u1 = (User)context.getBean("u1");
        User u2 = (User)context.getBean("u1");

//        System.out.println(u1.getId());
//        System.out.println(u1==u2);
        System.out.println(u1.getCompany().getCid());
    }
}

4、常用的地方

Controller依赖service;

Service依赖Dao;

Dao依赖DBUtil;

5、IOC和DI是同一概念

都是spring容器管理bean。只是侧重点和描述同一事物的角度不同,ioc从创建的角度描述,di是对象之间的关系角度描述的。

六、bean配置信息详解

1、常用配置

id 对象的编号(唯一),我们需要通过它找到spring容器的对象

name 对象的名称(唯一,可以有多个名字),我们需要通过它找到spring容器的对象

class 要管理的类,spring容器会创建该类的对象(反射)

2、scope

bean的作用范围:

singleton 单例(默认)

prototype 多例,每次获取都会返回一个新对象

request 一次请求中,多次获取的都是同一个对象

session 一次会话,多次获取的都是同一个对象

3、生命周期的方法:

init-method="init方法名"
destroy-method="destroy"

4、单例的饿汉和懒汉

lazy-init

默认false,采用饿汉模式

true,采用懒汉模式。

七、属性注入方式

1、setter方法注入

(1)必须为属性提供setter方法

(2)在bean标签中使用

<property      name="属性名"    ref="被注入的对象id"></property>
package com.hs;

public class User {
    private   int  id;
    private  String  name;
    private   String  username;
    private  String  passwd;
//    依赖注入
    private  Company   company;

    public Company getCompany() {
        return company;
    }

    public void setCompany(Company company) {
        this.company = company;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPasswd() {
        return passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }
}
package com.hs;

public class Company {
    private  int  cid;
    private  int  cname;

    public  void   init(){
        System.out.println("初始化");
    }


    public   void  destroy(){
        System.out.println("销毁");
    }

    public int getCid() {
        return cid;
    }

    public void setCid(int cid) {
        this.cid = cid;
    }

    public int getCname() {
        return cname;
    }

    public void setCname(int cname) {
        this.cname = cname;
    }
}
<?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">


    <!--将com.hs.User交给spring容器创建和管理-->
    <!--默认bean对象是单例的-->
    <!--id和name作用相同,一般使用id-->
    <!--class是要实例化的类,包名.类名-->
    <bean   id="u1"   name="u1"  class="com.hs.User"  scope="prototype"  >
        <property name="company" ref="cm"></property>
    </bean>

    <bean  id="cm"   class="com.hs.Company"    scope="singleton" init-method="init"  destroy-method="destroy"  lazy-init="true"></bean>

</beans>

2、构造器注入

package com.hs;

public class Student {
    public  int  id;
    public  String  name;
    public  Clazz   clazz;

    public Student(int id, String name, Clazz clazz) {
        this.id = id;
        this.name = name;
        this.clazz = clazz;
    }



}
package com.hs;

public class Clazz {
    private  int  cid;
    private  String  cname;

    public int getCid() {
        return cid;
    }

    public void setCid(int cid) {
        this.cid = cid;
    }

    public String getCname() {
        return cname;
    }

    public void setCname(String cname) {
        this.cname = cname;
    }
}
<!--    构造器注入-->
    <bean  id="clazz"  class="com.hs.Clazz"></bean>
    <bean  id="student" class="com.hs.Student">
        <constructor-arg index="0" value="1001"></constructor-arg>
        <constructor-arg index="1"  value="张三"></constructor-arg>
        <constructor-arg  index="2"  ref="clazz"></constructor-arg>
    </bean>

3、p空间注入

还是采用setter方法注入

只是简化的写法。

package com.hs;

public class Emp {
    private  int  id;
    private  String  name;
    private  Dept    dept;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }
}
package com.hs;

public class Dept {
    private   int  did;
    private   String  dname;

    public int getDid() {
        return did;
    }

    public void setDid(int did) {
        this.did = did;
    }

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        this.dname = dname;
    }
}

第一步,引用p空间

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

第二步,使用p空间

<!--    p空间注入-->
    <bean id="dept" class="com.hs.Dept"></bean>
    <bean   id="emp"  class="com.hs.Emp"  p:id="9001" p:name="李萧" p:dept-ref="dept"></bean>

4、字段注入(注解)

注解

@AutoWired

@Resource

八、属性装配

使用注入的方式给属性赋值

1、简单类型属性

byte short int long

char boolean String

2、复杂类型

数组、List、Set、Map

3、对象

package com.hs;

import java.util.List;
import java.util.Map;
import java.util.Set;

public class Wired {
    private  int   aa;
    private  double  bb;
    private  char    cc;
    private   boolean  dd;
    private   String  ee;
    private   String[]   ff;
    private List<String> gg;
    private Set<String> hh;
    private Map<String,String> ii;
    private HS    hs;

    public HS getHs() {
        return hs;
    }

    public void setHs(HS hs) {
        this.hs = hs;
    }

    public int getAa() {
        return aa;
    }

    public void setAa(int aa) {
        this.aa = aa;
    }

    public double getBb() {
        return bb;
    }

    public void setBb(double bb) {
        this.bb = bb;
    }

    public char getCc() {
        return cc;
    }

    public void setCc(char cc) {
        this.cc = cc;
    }

    public boolean isDd() {
        return dd;
    }

    public void setDd(boolean dd) {
        this.dd = dd;
    }

    public String getEe() {
        return ee;
    }

    public void setEe(String ee) {
        this.ee = ee;
    }

    public String[] getFf() {
        return ff;
    }

    public void setFf(String[] ff) {
        this.ff = ff;
    }

    public List<String> getGg() {
        return gg;
    }

    public void setGg(List<String> gg) {
        this.gg = gg;
    }

    public Set<String> getHh() {
        return hh;
    }

    public void setHh(Set<String> hh) {
        this.hh = hh;
    }

    public Map<String, String> getIi() {
        return ii;
    }

    public void setIi(Map<String, String> ii) {
        this.ii = ii;
    }
}
package com.hs;

public class HS {
    private   int  hid;
    private  String  hname;

    public int getHid() {
        return hid;
    }

    public void setHid(int hid) {
        this.hid = hid;
    }

    public String getHname() {
        return hname;
    }

    public void setHname(String hname) {
        this.hname = hname;
    }
}
<bean  id="wired"  class="com.hs.Wired">
    <property name="aa" value="1001"></property>
    <property name="bb" value="12.5"></property>
    <property name="cc"  value="a"></property>
    <property name="dd" value="true"></property>
    <property name="ee" value="abcdefg"></property>
    <property name="ff">
        <array>
            <value>11</value>
            <value>12</value>
            <value>13</value>
            <value>14</value>
        </array>
    </property>
    <property name="gg" >
        <list>
            <value>21</value>
            <value>22</value>
            <value>23</value>
        </list>
    </property>
    <property name="hh" >
        <set>
            <value>31</value>
            <value>32</value>
            <value>33</value>
        </set>
    </property>
    <property name="ii" >
        <map>
            <entry key="41"  value="41"></entry>
            <entry key="42"  value="42"></entry>
            <entry key="43"  value="43"></entry>
        </map>
    </property>
    <property name="hs"   ref="hs"></property>
</bean>
<bean   id="hs"  class="com.hs.HS"></bean>

九、spring-web

1、Java项目中封装工具类

package com.hs.util;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringUtil {
    private  static ApplicationContext context;

    static{
        context=new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    }
    
    public   static   <T>   T   getBean(String  id){
        return   (T)context.getBean(id);
    }
}

2、web项目开发

依然可以使用这个工具类来获取spring容器中的对象。

有没有更好的解决方案呢?

我们在启动tomat时,交给tomcat完成spring容器的初始化。

原理:

利用了上下文监听器实现。

当启动tomcat,tomcat创建一上下文对象,监听器对其处理:

初始化一个spring容器,放入上下文对象存储 。

实现:

package com.hs.web;


import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class SpringServletContextListener implements ServletContextListener {
    ClassPathXmlApplicationContext   context;

    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        //初始化spring容器
        context=new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        //放入上下文对象中
        servletContextEvent.getServletContext().setAttribute("spring",context);

    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
//        移除上下文
        servletContextEvent.getServletContext().removeAttribute("spring");
//        销毁spring容器
        context.close();
    }
}

3、spring-web

刚才写的代码在spring-web中实现好了。

就不需要我们实现了。

(1)引入spring-web依赖

<!--    spring-web-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>4.3.14.RELEASE</version>
    </dependency>

(2)web.xml配置监听器

<!--  spring配置文件的路径-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>

<!--  上下文监听器-->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

4、spring容器主要用来管理哪些bean

主要用于管理controller,service,dao

问题:

tomcat接受请求,根据url找servlet。

tomat去servlet容器中找,不会去spring容器中找。

如果想要tomcat去spring容器中找,使用springmvc框架。

十、多配置文件

1、配置文件拆分

所有信息配置到一个xml中,内容过长,不方便阅读。

可以对配置信息进行分类:

applicationContext-dao.xml 配置dao

applicationContext-service.xml 配置service

applicationContext-controller.xml 配置controller

applicationContext-base.xml 配置基本信息

2、Java项目

ApplicationContext  context=new ClassPathXmlApplicationContext("classpath*:applicationContext*.xml");

3、web项目

<!--  spring配置文件的路径-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext*.xml</param-value>
  </context-param>

十一、IOC注解形式

1、@Component注解

配置一个bean,交给spring容器托管。

比如:

@Component(“clz”)

等价:

package com.hs.domain;


import org.springframework.stereotype.Component;

@Component("clz")
public class Clazz {
    private   int  cid;
    private   String  cname;

    public int getCid() {
        return cid;
    }

    public void setCid(int cid) {
        this.cid = cid;
    }

    public String getCname() {
        return cname;
    }

    public void setCname(String cname) {
        this.cname = cname;
    }
}

2、配置注解扫描

<?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="com.hs"></context:component-scan>
</beans>

3、测试

package com.hs.test;

import com.hs.domain.Clazz;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

public class TestDemo {

    @Test
    public  void  test1(){
//        spring容器的初始化
        ApplicationContext  context=new ClassPathXmlApplicationContext("classpath:applicationContext.xml");

//        获取bean
        Clazz clz=(Clazz) context.getBean("clz");
        System.out.println(clz);
    }

}

4、其他bean注解

@Component有三个常用的子类:

@Controller controller bean

@Service service bean

@Repository dao bean

5、依赖注入

(1)@Autowired

按类型装配

(2)@Resource

按名字装配

package com.hs.domain;


import org.springframework.stereotype.Component;

@Component("clz")
public class Clazz {
    private   int  cid;
    private   String  cname;

    public int getCid() {
        return cid;
    }

    public void setCid(int cid) {
        this.cid = cid;
    }

    public String getCname() {
        return cname;
    }

    public void setCname(String cname) {
        this.cname = cname;
    }
}

十二、登录案例

1、登录的页面

<%--
  Created by IntelliJ IDEA.
  User: HS
  Date: 2021/9/16
  Time: 16:00
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="/login"   method="get">
        用户名:<input  type="text"  name="username"><br>
        密码:<input  type="password"  name="passwd"><br>
        <input  type="submit"  value="登录">
    </form>
</body>
</html>

2、domain

package com.hs.domain;

public class Emp {
    private  int  e_id;
    private  String   e_name;
    private  String   e_sex;
    private  String   e_tel;
    private  String  username;
    private  String  passwd;

    public int getE_id() {
        return e_id;
    }

    public void setE_id(int e_id) {
        this.e_id = e_id;
    }

    public String getE_name() {
        return e_name;
    }

    public void setE_name(String e_name) {
        this.e_name = e_name;
    }

    public String getE_sex() {
        return e_sex;
    }

    public void setE_sex(String e_sex) {
        this.e_sex = e_sex;
    }

    public String getE_tel() {
        return e_tel;
    }

    public void setE_tel(String e_tel) {
        this.e_tel = e_tel;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPasswd() {
        return passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }
}

3、DBUtil

4、Dao

package com.hs.dao.impl;

import com.hs.dao.EmpDao;
import com.hs.domain.Emp;
import com.hs.util.DBUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.sql.ResultSet;
import java.sql.SQLException;

@Repository
public class EmpDaoImpl implements EmpDao {
    @Autowired
    private  DBUtil  dbUtil;

    @Override
    public Emp findEmpByUsername(String username) {
        String  sql="select *  from  emp  where  username=?";
        Object[]    objs={username};
        ResultSet rs = dbUtil.select(sql, objs);
        Emp  emp=null;
        try {
            if(rs.next()){
                emp=new Emp();
                emp.setE_id(rs.getInt("e_id"));
                emp.setE_name(rs.getString("e_name"));
                emp.setE_sex(rs.getString("e_sex"));
                emp.setE_tel(rs.getString("e_tel"));
                emp.setUsername(rs.getString("username"));
                emp.setPasswd(rs.getString("passwd"));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            dbUtil.close();
        }
        return emp;
    }
}

5、Service

package com.hs.service.impl;

import com.hs.dao.EmpDao;
import com.hs.domain.Emp;
import com.hs.service.EmpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class EmpServiceImpl   implements EmpService {
    @Autowired
    private EmpDao   empDao;

    @Override
    public int login(String username, String passwd) {
        Emp emp = empDao.findEmpByUsername(username);
        if(emp==null){
            return  0;
        }
        if(emp.getPasswd().equals(passwd)){
            return  2;
        }
        return 1;
    }
}

6、pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.hs</groupId>
  <artifactId>springDemo02</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>springDemo02 Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.14.RELEASE</version>
    </dependency>

<!--    <dependency>-->
<!--      <groupId>org.springframework</groupId>-->
<!--      <artifactId>spring-web</artifactId>-->
<!--      <version>4.3.14.RELEASE</version>-->
<!--    </dependency>-->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.0.1</version>
    </dependency>

    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>javax.servlet.jsp-api</artifactId>
      <version>2.3.0</version>
    </dependency>

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.16</version>
    </dependency>

  </dependencies>

  <build>
    <finalName>springDemo02</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

7、springUtil

package com.hs.util;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringUtil {
        private  static ApplicationContext context;

        static{
            context=new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        }

        public   static   <T>   T   getBean(String  id){
            return   (T)context.getBean(id);
        }
}

8、Controller

package com.hs.controller;

import com.hs.service.EmpService;
import com.hs.util.SpringUtil;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/login")
//对象保存在tomcat的servlet容器
public class EmpController extends HttpServlet {
    //不能注入,因为EmpController在tomcat容器中,不放入spring容器中
    private EmpService  empService;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1
        String username = req.getParameter("username");
        String passwd = req.getParameter("passwd");

        //2
        empService=SpringUtil.getBean("empService");
        int login = empService.login(username, passwd);

        //3
        if(login==0){
            resp.sendRedirect("/login.jsp");
        }
        if(login==1){
            resp.sendRedirect("/login.jsp");
        }
        if(login==2){
            resp.sendRedirect("/index.jsp");
        }

    }
}

十三、AOP

1、动态代理

jdk动态代理:目标对象需要接口

cglib动态代理:目标对象不需要接口

2、AOP

面向切面编程,是对OOP的补充。

底层采用的就是动态代理实现的。

如果目标对象没有实现接口,采用cglib动态代理。

如果目标对象实现接口,采用jdk动态代理。

3、AOP原理(日志管理)

目标接口1:

package com.hs.service.impl;

public interface ILoginService {
    void  add();
    void  delete();
    void  update();
    void  select();
}

目标实现类1:

package com.hs.service.impl;

import java.util.Date;

public class LogService implements   ILoginService{
    //Log  log=new Log();

    public  void  add(){
        //log.before();
        System.out.println("add");
        //log.after();
    }

    public  void   delete(){
        //log.before();
        System.out.println("delete");
        //log.after();
    }

    public   void   update(){
        //log.before();
        System.out.println("update");
        //log.after();
    }

    public  void   select(){
        //log.before();
        System.out.println("select");
        //log.after();
    }


}

目标类2:

package com.hs.service.impl;

public class LogService2 {
    //Log  log=new Log();

    public  void  add(){
        //log.before();
        System.out.println("add");
        //log.after();
    }

    public  void   delete(){
        //log.before();
        System.out.println("delete");
        //log.after();
    }

    public   void   update(){
        //log.before();
        System.out.println("update");
        //log.after();
    }

    public  void   select(){
        //log.before();
        System.out.println("select");
        //log.after();
    }
}

日志打印类:

package com.hs.service.impl;

import java.util.Date;

public class Log {
    public   void  before(){
        System.out.println("开始执行:"+new Date());
    }

    public  void  after(){
        System.out.println("执行结束:"+new Date());
    }
}

jdk代理工具类:

package com.hs.service.impl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JDK implements InvocationHandler {
    private  Object   target;
    private  Log    log=new Log();
    public  JDK(Object   target){
        this.target=target;
    }

//    目标方法的增强
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("jdk:");
        log.before();
        Object invoke = method.invoke(target, args);
        log.after();
        return  invoke;
    }

//  获取代理对象
    public  <T>   T   getProxy(){
        return (T)Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }
}

cglib代理工具类:需要导入cglib依赖

package com.hs.service.impl;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.annotation.Target;
import java.lang.reflect.Method;

public class CgLib implements MethodInterceptor {
    private  Object   target;
    private  Log    log=new Log();
    public  CgLib(Object   target){
        this.target=target;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib:");
        log.before();
        Object invoke = method.invoke(target, objects);
        log.after();
        return  invoke;
    }


//    目标方法的增强
    public  <T>   T   getProxy(){
        Enhancer    en=new Enhancer();
        en.setCallback(this);
        en.setSuperclass(target.getClass());
        return   (T)en.create();
    }

}

获取代理对象:根据判断选择代理模式

package com.hs.service.impl;

public class AOPDemo {

    public   static  Object  getProxy(Object   target){
        Class<?>[] interfaces = target.getClass().getInterfaces();
        if(interfaces.length==0){
            //cglib
            CgLib  cgLib=new CgLib(target);
            //proxy
            return cgLib.getProxy();
        }else{
            //jdk
            JDK  jdk=new JDK(target);
            return  jdk.getProxy();

        }
    }

}

测试类:

package com.hs.service.impl;

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

        LogService   ls1=new LogService();
        LogService2   ls2=new LogService2();

        ILoginService  poxy1=(ILoginService)AOPDemo.getProxy(ls1);
        LogService2  poxy2=(LogService2)AOPDemo.getProxy(ls2);

        poxy1.add();
        poxy1.delete();
        poxy1.update();
        poxy1.select();

        poxy2.add();
        poxy2.delete();
        poxy2.update();
        poxy2.select();

    }
}

4、spring-aop概念

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wQ3hgkkN-1632315227626)(spring框架.assets/image-20210916172515966.png)]

切面:通知+切点

通知:切面类中定义的用于增强的方法before、after

连接点:被增强的目标对象的方法。add,delete,update,select

切点:它是一个描述,对哪些连接点进行增强。

5、spring -aop实现方案

(1)spring aop技术

(2)aspectj技术(推荐)

6、spring - Aop实现

(1)导入依赖

spring-aop

cglib

aopalliance-1.0.jar

aspectj

aspectjweaver.jar

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.hs</groupId>
  <artifactId>springDemo02</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>springDemo02 Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.14.RELEASE</version>
    </dependency>

<!--    <dependency>-->
<!--      <groupId>org.springframework</groupId>-->
<!--      <artifactId>spring-web</artifactId>-->
<!--      <version>4.3.14.RELEASE</version>-->
<!--    </dependency>-->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.0.1</version>
    </dependency>

    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>javax.servlet.jsp-api</artifactId>
      <version>2.3.0</version>
    </dependency>

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.16</version>
    </dependency>


    <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib</artifactId>
      <version>2.2.2</version>
    </dependency>

    <dependency>
      <groupId>aopalliance</groupId>
      <artifactId>aopalliance</artifactId>
      <version>1.0</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>1.8.0</version>
      <scope>runtime</scope>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.0</version>
      <scope>runtime</scope>
    </dependency>


  </dependencies>

  <build>
    <finalName>springDemo02</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

(2)目标类

package com.hs.service.impl;

public interface ILoginService {
    void  add();
    void  delete();
    void  update();
    void  select();
}
package com.hs.service.impl;

import java.util.Date;
public class LogService implements   ILoginService{
    //Log  log=new Log();

    public  void  add(){
        //log.before();
        System.out.println("add");
        //log.after();
    }

    public  void   delete(){
        //log.before();
        System.out.println("delete");
        //log.after();
    }

    public   void   update(){
        //log.before();
        System.out.println("update");
        //log.after();
    }

    public  void   select(){
        //log.before();
        System.out.println("select");
        //log.after();
    }


}
package com.hs.service.impl;

public class LogService2 {
    //Log  log=new Log();

    public  void  add(){
        //log.before();
        System.out.println("add");
        //log.after();
    }

    public  void   delete(){
        //log.before();
        System.out.println("delete");
        //log.after();
    }

    public   void   update(){
        //log.before();
        System.out.println("update");
        //log.after();
    }

    public  void   select(){
        //log.before();
        System.out.println("select");
        //log.after();
    }
}

(3)编写切面类


public class Log {
    public   void  before(){
        System.out.println("开始执行:"+new Date());
    }

    public  void  after(){
        System.out.println("执行结束:"+new Date());
    }
}

(4)配置aop

<!--    1、目标类-->
    <bean id="ls1" class="com.hs.service.impl.LogService"></bean>
    <bean id="ls2" class="com.hs.service.impl.LogService2"></bean>

<!--    2、切面类-->
    <bean  id="log"  class="com.hs.service.impl.Log"></bean>

<!--    3、aop配置-->
    <aop:config>
<!--        切面-->
        <aop:aspect id="litong" ref="log">
<!--             切点:定义对谁增强的描述-->
                <aop:pointcut id="logCut" expression="execution(public void com.hs.service.impl.*.*(..))"/>
<!--            通知:-->
                <aop:before method="before"  pointcut-ref="logCut"></aop:before>
                <aop:after method="after"  pointcut-ref="logCut"></aop:after>
        </aop:aspect>
    </aop:config>

(5)测试

@Test
public   void  testAop(){
    ApplicationContext  context=new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    ILoginService ls1 = (ILoginService) context.getBean("ls1");
    LogService2 ls2 = (LogService2) context.getBean("ls2");

    ls1.add();
    ls2.add();
}

7、切点表达式

(1)切点用于选择给哪些连接点做增强。

<aop:pointcut id=“切点名称” expression=“execution(选择的方法)”/>

(2)切点表达式

精准匹配

execution(public void com.hs.UserService.add(int,String))

参数模糊匹配

execution(public void com.hs.UserService.add(…))

方法名模糊匹配

execution(public void com.hs.UserService.*(…))

类名模糊匹配

execution(public void com.hs. * . * (…))

包名模糊匹配

execution(public void *. * . * (…))

返回值类型模糊匹配

execution(public * *. * . * (…))

修饰符模糊匹配

execution(* * *. * . * (…))

execution(* (…))

8、通知类型

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjtools -->
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjtools</artifactId>
  <version>1.8.0</version>
</dependency>

(1)前置通知before

在目标方法之前织入。

可以没有参数,也可以有参数,比如JoinPoint。

(2)后置通知after-retuning

在目标方法之后织入。

(3)环绕通知around

(4)最终通知after

(5)异常通知after-throwing

package com.hs.service.impl;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

import java.util.Date;

public class Log {
    public   void  before(JoinPoint  jp){
        System.out.println(jp.getSignature().getName());
        System.out.println("开始执行:"+new Date());
    }

    public  void  after(JoinPoint  jp){
        System.out.println(jp.getSignature().getName());
        System.out.println("执行结束:"+new Date());
    }

    public  void  afterReturning(JoinPoint  jp){
        System.out.println(jp.getSignature().getName());
        System.out.println("后置通知执行结束:"+new Date());
    }

    public   void   round(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("环绕执行开始:"+new Date());
        Object  result=jp.proceed();//执行目标方法
        System.out.println("执行结果是:"+result);
        System.out.println("环绕执行结束:"+new  Date());
    }


    public   void   exception(JoinPoint  jp,Throwable  e){
        System.out.println("方法名:"+jp.getSignature().getName());
        System.out.println(e);
        System.out.println("异常通知");
    }
}
<aop:config>
<!--        切面-->
        <aop:aspect id="litong" ref="log">
<!--             切点:定义对谁增强的描述-->
                <aop:pointcut id="logCut" expression="execution(public void com.hs.service.impl.*.*(..))"/>
<!--            通知:-->
                <aop:before method="before"  pointcut-ref="logCut"></aop:before>
                <aop:after method="after"  pointcut-ref="logCut"></aop:after>
                <aop:around method="round"   pointcut-ref="logCut"></aop:around>
                <aop:after-throwing throwing="e" method="exception"   pointcut-ref="logCut"></aop:after-throwing>
                <aop:after-returning method="afterReturning" pointcut-ref="logCut"></aop:after-returning>
        </aop:aspect>
    </aop:config>

通知执行顺序:

前置通知

异常通知

后置通知

最终通知

环绕通知和配置的先后顺序有关!!!

十四、AOP注解形式

1、bean的配置

开启注解扫描:

<!--注解扫描-->
<context:component-scan base-package="com.hs"></context:component-scan>

配置目标对象:

package com.hs.service.impl;

public interface ILoginService {
    void  add();
    void  delete();
    void  update();
    void  select();
}
package com.hs.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.util.Date;

@Service
public class LogService implements   ILoginService{

    //Log  log=new Log();

    public  void  add(){
        int  i=0;
//        System.out.println(10/i);
        //log.before();
        System.out.println("add");
        //log.after();
    }

    public  void   delete(){
        //log.before();
        System.out.println("delete");
        //log.after();
    }

    public   void   update(){
        //log.before();
        System.out.println("update");
        //log.after();
    }

    public  void   select(){
        //log.before();
        System.out.println("select");
        //log.after();
    }




}
package com.hs.service.impl;

import org.springframework.stereotype.Service;
@Service
public class LogService2 {
    //Log  log=new Log();

    public  void  add(){
        //log.before();
        System.out.println("add");
        //log.after();
    }

    public  void   delete(){
        //log.before();
        System.out.println("delete");
        //log.after();
    }

    public   void   update(){
        //log.before();
        System.out.println("update");
        //log.after();
    }

    public  void   select(){
        //log.before();
        System.out.println("select");
        //log.after();
    }
}

切面类:

package com.hs.service.impl;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class Log {
    public   void  before(JoinPoint  jp){
        System.out.println(jp.getSignature().getName());
        System.out.println("开始执行:"+new Date());
    }

    public  void  after(JoinPoint  jp){
        System.out.println(jp.getSignature().getName());
        System.out.println("执行结束:"+new Date());
    }

    public  void  afterReturning(JoinPoint  jp){
        System.out.println(jp.getSignature().getName());
        System.out.println("后置通知执行结束:"+new Date());
    }

    public   void   round(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("环绕执行开始:"+new Date());
        Object  result=jp.proceed();//执行目标方法
        System.out.println("执行结果是:"+result);
        System.out.println("环绕执行结束:"+new  Date());
    }


    public   void   exception(JoinPoint  jp,Throwable  e){
        System.out.println("方法名:"+jp.getSignature().getName());
        System.out.println(e);
        System.out.println("异常通知");
    }
}

2、配置切面

@Aspect

切面=切点+通知

package com.hs.service.impl;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
@Aspect
public class Log {

    @Pointcut("execution(public void com.hs.service.impl.LogService*.*(..))")
    public   void   pointCut(){}


    @Before("pointCut()")
    public   void  before(JoinPoint  jp){
        System.out.println(jp.getSignature().getName());
        System.out.println("开始执行:"+new Date());
    }

    @After("pointCut()")
    public  void  after(JoinPoint  jp){
        System.out.println(jp.getSignature().getName());
        System.out.println("执行结束:"+new Date());
    }

    @AfterReturning("pointCut()")
    public  void  afterReturning(JoinPoint  jp){
        System.out.println(jp.getSignature().getName());
        System.out.println("后置通知执行结束:"+new Date());
    }

    @Around("pointCut()")
    public   void   round(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("环绕执行开始:"+new Date());
        Object  result=jp.proceed();//执行目标方法
        System.out.println("执行结果是:"+result);
        System.out.println("环绕执行结束:"+new  Date());
    }

    @AfterThrowing(pointcut = "pointCut()",throwing = "e")
    public   void   exception(JoinPoint  jp,Throwable  e){
        System.out.println("方法名:"+jp.getSignature().getName());
        System.out.println(e);
        System.out.println("异常通知");
    }
}

3、开启aop注解

<!-- 开启 aop注解扫描  -->
<aop:aspectj-autoproxy />

4、通知执行顺序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4vkCKIZp-1632315227628)(spring框架.assets/N@FID8U[6KH%DHKZ52NSI@9.png)]

使用注解后,执行的顺序固定,方法的顺序不会影响执行的顺序

十五、spring jdbc

1、spring jdbc

对jdbc进行了封装,和我们的dbUtil类似,封装成了一个工具类JdbcTemplate。

2、导入依赖

spring-jdbc

spring-tx

<!--    spring  jdbc-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>4.3.14.RELEASE</version>
    </dependency>

3、配置数据源

可以直接配置,也可以使用属性文件配置。


<!--    spring  jdbc -->
<!--    数据源-->
<!--    <bean  id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">-->
<!--        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>-->
<!--        <property name="url" value="jdbc:mysql:///hscrm?serverTimezone=Asia/Shanghai"></property>-->
<!--        <property name="username"  value="root"></property>-->
<!--        <property name="password"  value="root"></property>-->
<!--    </bean>-->

    <context:property-placeholder location="db.properties"></context:property-placeholder>
    <bean  id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${hs.jdbc.driverName}"></property>
        <property name="url" value="${hs.jdbc.url}"></property>
        <property name="username"  value="${hs.jdbc.username}"></property>
        <property name="password"  value="${hs.jdbc.password}"></property>
    </bean>


4、配置jdbcTemplate

<!--    jdbcTemplate-->
    <bean  id="jdbcTemplate"  class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource"   ref="dataSource"></property>
    </bean>

5、dao层使用jdbcTemplate完成CURD操作

(1)单行查询

//    queryForObject查询结果最多一行
	public Emp findEmpByUsername(String username){
        String  sql="select *  from  emp  where  username=?";

//        Emp emp = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Emp>(Emp.class), username);
        Object[]  objs={username};
        try {
            Emp emp = jdbcTemplate.queryForObject(sql, objs, new BeanPropertyRowMapper<Emp>(Emp.class));
            return  emp;
        }catch (Exception  e){
            return  null;
        }

    }

(2)查询多行

//    查询所有
    public List<Emp> findAllEmp(){
        String  sql="select  *  from  emp";
        List<Emp> empList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class));
        return  empList;
    }

(3)添加数据

//    添加
    public   int   addEmp(Emp  emp){
        String  sql="insert  into  emp  values(null,?,?,?,?,?)";
        int  i=jdbcTemplate.update(sql,emp.getE_name(),emp.getE_sex(),emp.getE_tel(),emp.getUsername(),emp.getPasswd());
        return   i;
    }

(4)修改数据

//    修改
public   int   updateEmp(Emp  emp){
    String  sql="update   emp  set  e_name=?,e_sex=?,e_tel=?,username=?,passwd=?  where  e_id=?";
    int  i=jdbcTemplate.update(sql,emp.getE_name(),emp.getE_sex(),emp.getE_tel(),emp.getUsername(),emp.getPasswd(),emp.getE_id());
    return   i;
}

(5)删除数据

//    删除
public   int   deleteEmp(int  e_id){
    String  sql="delete  from  emp  where  e_id=?";
    int  i=jdbcTemplate.update(sql,e_id);
    return   i;
}

十六、事务管理

1、事务

在数据库中,用于完成一个功能的多个操作的集合。

比如:转账。

转账是一个事务,这个事务中包含两个操作,转出方扣钱,转入方加钱。

2、事务的特性ACID

(1)原子性

多个操作构成一个整体,不可分割。

(2)一致性

事务中的所有操作要么全部成功,要么全部失败。

(3)隔离性

可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。

多个事务并发访问同一数据,可以设计隔离级别。

隔离级别越高,数据不一致问题影响越小,效率越低。

(4)持久性

一旦事务完成,数据永久存储。

3、spring事务管理

(1)spring框架对事务管理进行了封装

在数据库中:

获取事务;

执行事务中的所有操作;

如果发生异常,回滚所有操作rollback;

如果所有操作都没有异常,提交事务commit。

spring框架对其进行了封装:

spring事务管理主要用于service层。

获取一个事务;

执行service层的业务操作方法;

如果方法中没有异常,执行commit,数据库生效。

如果方法中有异常,执行rollback,数据库回滚。

4、spring事务管理器

Spring并不直接管理事务,而是提供了多种事务管理器。

Spring事务管理器的接口是org.springframework.transaction.PlatformTransactionManager,通过这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。

Public interface PlatformTransactionManager()...{  
    // 由TransactionDefinition得到TransactionStatus对象
    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; 
    // 提交
    Void commit(TransactionStatus status) throws TransactionException;  
    // 回滚
    Void rollback(TransactionStatus status) throws TransactionException;  
    } 
public interface TransactionDefinition {
    int getPropagationBehavior(); // 返回事务的传播行为
    int getIsolationLevel(); // 返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据
    int getTimeout();  // 返回事务必须在多少秒内完成
    boolean isReadOnly(); // 事务是否只读,事务管理器能够根据这个返回值进行优化,确保事务是只读的
} 

5、spring事务管理形式

(1)编程式事务管理

使用spring框架提供的api,自己写代码,实现事务管理。

try{

​ //事务操作

​ //事务提交

}catch(e){

​ //事务回滚

}

缺点:代码耦合度比较高。

优点:细粒度管理。

(2)声明式事务管理

底层是通过aop实现的。

不需要你写代码,配置一下就可以了。

配置形式:xml和注解。

优点:统一管理,低耦合。

缺点:粗细度管理。

十七、spring-声明式事务管理xml

1、问题案例:转账

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       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
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
">


    <!--注解扫描-->
    <context:component-scan base-package="com.hs"></context:component-scan>

    <bean  id="dataSource"   class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName"  value="com.mysql.cj.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql:///hscrm?serverTimezone=Asia/Shanghai"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

</beans>

(1)数据库

CREATE TABLE `account` (
  `aid` int(11) NOT NULL,
  `aname` varchar(255) COLLATE utf8_bin DEFAULT NULL,
  `banlance` double(255,0) DEFAULT NULL,
  `apasswd` varchar(255) COLLATE utf8_bin DEFAULT NULL,
  PRIMARY KEY (`aid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

(2)dao层

package com.hs.domain;

public class Account {
    private   int  aid;
    private   String  aname;
    private   double  banlance;
    private   String  apasswd;

    public int getAid() {
        return aid;
    }

    public void setAid(int aid) {
        this.aid = aid;
    }

    public String getAname() {
        return aname;
    }

    public void setAname(String aname) {
        this.aname = aname;
    }

    public double getBanlance() {
        return banlance;
    }

    public void setBanlance(double banlance) {
        this.banlance = banlance;
    }

    public String getApasswd() {
        return apasswd;
    }

    public void setApasswd(String apasswd) {
        this.apasswd = apasswd;
    }
}
package com.hs.dao;

import com.hs.domain.Account;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class AccountDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * 转入:加钱
     */
    public   void   addMoney(Account  acc,double money){
        String  sql="update  account  set  banlance=?  where  aid=?";
        Object[]   objs={acc.getBanlance()+money,acc.getAid()};
        jdbcTemplate.update(sql,objs);
    }

    /**
     * 转出:扣钱
     */
    public   void   subMoney(Account  acc,double money){
        String  sql="update  account  set  banlance=?  where  aid=?";
        Object[]   objs={acc.getBanlance()-money,acc.getAid()};
        jdbcTemplate.update(sql,objs);
    }

}

(3)service层

package com.hs.service;

import com.hs.dao.AccountDao;
import com.hs.domain.Account;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class AccountService {

    @Autowired
    private AccountDao  accountDao;

    /**
     * 转账
     */
    public  void   transform(Account  acc1, Account  acc2,double   money){
        //扣钱
        accountDao.subMoney(acc1,money);
        //加钱
        accountDao.addMoney(acc2,money);
    }

}

(4)测试

package com.hs;

import com.hs.domain.Account;
import com.hs.service.AccountService;
import com.hs.util.SpringUtil;
import org.junit.Test;

public class Test1 {

    @Test
    public  void  test1(){
        AccountService accountService = SpringUtil.getBean(AccountService.class);

        Account  acc1=new Account();
        acc1.setAid(622001);
        acc1.setBanlance(5000);
        Account  acc2=new Account();
        acc2.setAid(622002);
        acc2.setBanlance(5000);

        accountService.transform(acc1,acc2,500);
    }

}

2、修改service,测试

package com.hs.service;

import com.hs.dao.AccountDao;
import com.hs.domain.Account;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class AccountService {

    @Autowired
    private AccountDao  accountDao;

    /**
     * 转账
     */
    public  void   transform(Account  acc1, Account  acc2,double   money){
        //扣钱
        accountDao.subMoney(acc1,money);

        //异常
        System.out.println(10/0);

        //加钱
        accountDao.addMoney(acc2,money);
    }

}

出现异常:

java.lang.ArithmeticException: / by zero

at com.hs.service.AccountService.transform(AccountService.java:22)
at com.hs.Test1.test1(Test1.java:21)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)

结果:扣钱成功,加钱失败

622001 zhangsan 4000 123456
622002 lisi 5500 123456

解决方案:事务管理。

3、spring声明式事务管理xml

基于aspectj配置事务管理:

<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjrt</artifactId>
  <version>1.8.0</version>
</dependency>
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.8.0</version>
</dependency>
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjtools</artifactId>
  <version>1.8.0</version>
</dependency>
<dependency>
  <groupId>cglib</groupId>
  <artifactId>cglib</artifactId>
  <version>2.2.2</version>
</dependency>

(1)配置事务管理器

<!--    第一步,配置事务管理器-->
<!--    指定数据源-->
    <bean  id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource"  ref="dataSource"></property>
    </bean>

(2)配置事务通知

<!--    第二步,配置事务通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--        事务属性:事务的传播性和隔离性,只读事务-->
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED" isolation="DEFAULT"/>
        </tx:attributes>
    </tx:advice>

(3)配置事务管理

<!--    第三步,配置aop切面-->
    <aop:config>
        <aop:pointcut id="cut" expression="execution(public  void com.hs.service.AccountService.transform(..))"/>
        <!--切面=切点+通知-->
        <aop:advisor advice-ref="txAdvice"  pointcut-ref="cut"></aop:advisor>
    </aop:config>

(4)测试

有异常时和没有异常时,看是否具有事务的一致性。

十八、事务管理注解形式

1、配置transactionManager

<!--    第一步,配置事务管理器-->
<!--    指定数据源-->
    <bean  id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource"  ref="dataSource"></property>
    </bean>

2、开启事务注解驱动

<!--    第二步,开启事务注解驱动-->
<tx:annotation-driven  transaction-manager="transactionManager"></tx:annotation-driven>

3、在service 层的方法前加注解

第三步,加事务注解@Transactional

package com.hs.service;

import com.hs.dao.AccountDao;
import com.hs.domain.Account;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class AccountService {

    @Autowired
    private AccountDao  accountDao;

    /**
     * 转账
     */
    @Transactional
    public  void   transform(Account  acc1, Account  acc2,double   money){
        //扣钱
        accountDao.subMoney(acc1,money);

        //异常
//        System.out.println(10/0);

        //加钱
        accountDao.addMoney(acc2,money);
    }

}

十九、事务属性

@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,readOnly = false)

1、事务的隔离级别

(1)并发事务引起的问题
在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务。并发虽然是必须的,但可能会导致一下的问题。

  • 脏读(Dirty reads)——脏读发生在一个事务读取了另一个事务改写但尚未提交的数据时。如果改写在稍后被回滚了,那么第一个事务获取的数据就是无效的。
  • 不可重复读(Nonrepeatable read)——不可重复读发生在一个事务执行相同的查询两次或两次以上,但是每次都得到不同的数据时。这通常是因为另一个并发事务在两次查询期间进行了更新。
  • 幻读(Phantom read)——幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录。

(2)隔离级别

隔离级别含义
ISOLATION_DEFAULT使用后端数据库默认的隔离级别
ISOLATION_READ_UNCOMMITTED最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
ISOLATION_READ_COMMITTED允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
ISOLATION_REPEATABLE_READ对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生
ISOLATION_SERIALIZABLE最高的隔离级别,完全服从ACID的隔离级别,确保阻止脏读、不可重复读以及幻读,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的

2、事务的传播性

spring定义了7中事务传播机制:
REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED)
支持当前事务,如果没有事务会创建一个新的事务
SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS)
支持当前事务,如果没有事务的话以非事务方式执行
MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY)
支持当前事务,如果没有事务抛出异常
REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW)
创建一个新的事务并挂起当前事务
NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED)
以非事务方式执行,如果当前存在事务则将当前事务挂起
NEVER(TransactionDefinition.PROPAGATION_NEVER)
以非事务方式进行,如果存在事务则抛出异常
NESTED(TransactionDefinition.PROPAGATION_NESTED)
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。

比如:

添加事务

方法a{

​	//操作1

​	//调用方法b

   //操作2

}

添加事务:事务的传播机制

方法b{

​	操作3

}

3、只读事务

readOnly = false

readOnly = true
cut id=“cut” expression=“execution(public void com.hs.service.AccountService.transform(…))”/>

<aop:advisor advice-ref=“txAdvice” pointcut-ref=“cut”></aop:advisor>
</aop:config>




(4)测试

有异常时和没有异常时,看是否具有事务的一致性。



## 十八、事务管理注解形式

### 1、配置transactionManager

<bean  id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource"  ref="dataSource"></property>
</bean>

### 2、开启事务注解驱动

<tx:annotation-driven transaction-manager=“transactionManager”></tx:annotation-driven>


### 3、在service 层的方法前加注解

第三步,加事务注解@Transactional

package com.hs.service;

import com.hs.dao.AccountDao;
import com.hs.domain.Account;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class AccountService {

@Autowired
private AccountDao  accountDao;

/**
 * 转账
 */
@Transactional
public  void   transform(Account  acc1, Account  acc2,double   money){
    //扣钱
    accountDao.subMoney(acc1,money);

    //异常

// System.out.println(10/0);

    //加钱
    accountDao.addMoney(acc2,money);
}

}




## 十九、事务属性

@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,readOnly = false)




### 1、事务的隔离级别

(1)并发事务引起的问题 
在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务。并发虽然是必须的,但可能会导致一下的问题。

> - 脏读(Dirty reads)——脏读发生在一个事务读取了另一个事务改写但尚未提交的数据时。如果改写在稍后被回滚了,那么第一个事务获取的数据就是无效的。
> - 不可重复读(Nonrepeatable read)——不可重复读发生在一个事务执行相同的查询两次或两次以上,但是每次都得到不同的数据时。这通常是因为另一个并发事务在两次查询期间进行了更新。
> - 幻读(Phantom read)——幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录。

(2)隔离级别

| 隔离级别                   | 含义                                                         |
| -------------------------- | ------------------------------------------------------------ |
| ISOLATION_DEFAULT          | 使用后端数据库默认的隔离级别                                 |
| ISOLATION_READ_UNCOMMITTED | 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读 |
| ISOLATION_READ_COMMITTED   | 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生 |
| ISOLATION_REPEATABLE_READ  | 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生 |
| ISOLATION_SERIALIZABLE     | 最高的隔离级别,完全服从ACID的隔离级别,确保阻止脏读、不可重复读以及幻读,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的 |



### 2、事务的传播性

spring定义了7中事务传播机制:
REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED)
支持当前事务,如果没有事务会创建一个新的事务
SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS)
支持当前事务,如果没有事务的话以非事务方式执行
MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY)
支持当前事务,如果没有事务抛出异常
REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW)
创建一个新的事务并挂起当前事务
NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED)
以非事务方式执行,如果当前存在事务则将当前事务挂起
NEVER(TransactionDefinition.PROPAGATION_NEVER)
以非事务方式进行,如果存在事务则抛出异常
NESTED(TransactionDefinition.PROPAGATION_NESTED)
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。





比如:

添加事务

方法a{

​ //操作1

​ //调用方法b

//操作2

}

添加事务:事务的传播机制

方法b{

​ 操作3

}








### 3、只读事务

readOnly = false

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值