浅浅记录——Spring5学习笔记

Spring5

Spring框架概述:

Spring是轻量级的开源的JavaEE框架

Spring能够解决企业应开发的复杂性

Spring有两个核心部分:IOC和AOP

  • IOC:控制反转,将创建对象的过程交给Spring进行管理

  • AOP:面向切面,不修改源代码进行功能增强

Spring特点

  • 方便解耦合

  • 支持AOP

  • 方便程序的测试

  • 方便整合各种其他的框架

  • 支持事务管理

IOC容器

IOC底层原理

概念:

  • 控制反转,将对象创建和对象之间的调用过程,交给Spring进行管理

  • 使用IOC的目的是为了降低耦合度

  • XML解析、工厂模式、反射

XML解析:使用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">
    <!--配置相关的对象-->
    <bean id="user" class="com.example.SpringLearning.User"></bean>

</beans>

工厂模式:为了降低代码的耦合度,使用工厂模式,将对象的创建,对象的获取分开,使用工厂类进行对象的创建并将创建的对象返回,在其他类中,如果需要使用某一个对象的时候,直接调用工厂类获得对象即可

反射:在工厂类中使用反射机制来创建指定的类

public class UserFactor {
    public static UserDao getUser() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring");
        Class user=Class.forName("user");
        return (UserDao) user.newInstance();
    }
}

IOC接口

  • IOC思想基于IOC 容器完成,IOC容器底层就是对象工厂

  • Spring提供IOC容器的两种实现方式,即两个接口

    • BeanFactory:IOC容器基本实现方式,是Spring内部使用的一种实现方式,一般适合开发人员进行使用。该接口的特点是在进行配置文件的加载的时候不会创建对象,只有获取对象的时候,才会创建对象

    • ApplicationContext:是上述接口的子接口,提供更多的强大的功能,一般由开发人员使用。使用该接口的时候,会在加载配置文件的时候就将配置文件中的所有的对象进行创建

    在实际开发中,使用第二种接口是比较好的。因为第二种方法,在服务器启动的时候就会将所有的对象都创建完毕,尽管这样使得项目部署的时间延长了,但是这样能将大部分的压力都转移到服务器启动的时期,在真正运行项目的时候,不会因为对象的创建耽误时间。也就是在用户进行访问的时候,系统的速度就会更快一点。

IOC的Bean管理操作

Bean管理,Bean管理指的是两个操作

  • Spring创建对象

  • Spring注入属性

Bean管理有两种方式来实现:

基于XML配置文件进行管理

<bean id="user" class="com.example.SpringLearning.User"></bean>

id属性:唯一标识

class属性:类的全路径

name属性:和id属性一样能用来作为标识,只不过id中不能使用特殊符号,但是name中能使用特殊符号,这个属性几乎不用

创建对象的时候默认使用的是无参构造进行创建

使用xml配置的方式为bean进行属性值的注入:

<bean id="user" class="com.example.SpringLearning.User">
    <property name="username" value="justin"></property>
    <property name="userid" value="123"></property>
</bean>

当然,也可以使用有参构造的方式进行属性值的注入:

<bean id="user" class="com.example.SpringLearning.User>
    <constructor-arg name="username" value="justin"></constructor-arg>
    <constructor-arg name="userid" value="123"></constructor-arg> 
</bean>

Bean实例化方法

  • 无参构造方法实例化

    UserDao.java

    public interface UserDao {
        public void save();
    }
    

    UserDaoImpl.java

    public class UserDaoImpl implements UserDao {
    
        public UserDaoImpl() {
            System.out.println("无参构造执行...");
        }
    
        public void save(){
            System.out.println("SAVE RUNNING...");
        }
    
    }
    
*UserDaoDemo.java*

```java
public class UserDaoDemo {
    public static void main(String[] args) {
        ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao) app.getBean("userDao");
        userDao.save();
    }
}

applivationContext.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">
    <!--配置相关的对象-->
    <bean id="userDao" class="alb.springlearning.impl.UserDaoImpl"></bean> <!--单例-->
</beans>
  • 工厂静态方法实例化

    UserDao.java

    public interface UserDao {
        public void save();
    }
    

    UserDaoImpl.java

    public class UserDaoImpl implements UserDao {
    
        public UserDaoImpl() {
            System.out.println("无参构造执行...");
        }
    
        public void save(){
            System.out.println("SAVE RUNNING...");
        }
    
    }
    

    StaticFactory.java

    public class StaticFactory {
        public static UserDao getUserDao() {
            return new UserDaoImpl();
        }
    }
    

    UserDaoDemo.java

    public class UserDaoDemo {
        public static void main(String[] args) {
            ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
            UserDao userDao = (UserDao) app.getBean("userDao");
            userDao.save();
        }
    }
    
  • 工厂实例方法实例化

依赖注入

依赖注入是Spring核心框架 IOC的具体实现

在编写程序的时候,通过控制反转将对象的创建交给了Spring,但是代码中不可能出现没有依赖的情况。IOC解耦合知识降低他们之间的依赖关系,但不会消除。例如:业务层仍会调用持久层的方法。

这种业务层和持久层之间的依赖关系,在使用Spring之后,就交给Spring来维护了。简单的说,就是坐等框架将持久层对象传入业务成,而不需要自己进行获取。

实现依赖注入的方式:

  • set方法

    UserServiceImpl.java

    public class UserServiceImpl implements UserService {
        private UserDao userDao;
    
        public void setUserDao(UserDao userDao) {
            this.userDao = userDao;
        }
    
        @Override
        public void save() {    //使用set方法之后,这里就不用再从容器中进行获取了,音容已经实现了依赖的注入
            userDao.save();
        }
    }
    

    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">
        <!--配置相关的对象-->
        <bean id="userDao" class="alb.springlearning.Factory.StaticFactory" factory-method="getUserDao"></bean>
    
        <!--单例-->
    
        <bean id="userService" class="alb.springlearning.service.impl.UserServiceImpl">
            <property name="userDao" ref="userDao"></property>
        </bean>
        <!--上述代码实现的功能就是将UserDao通过set方法将其注入到userService中-->
    </beans>
    
  • 构造方法

依赖注入的数据类型

  • 普通数据类型

    一般使用最多的就是set方法进行数据的注入

        <bean id="userDao" class="alb.springlearning.impl.UserDaoImpl">
            <property name="username" value="zhangsan"/>
            <property name="age" value="20"/>
        </bean>
    
  • 引用数据类型

  • 集合数据类型

    <?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="userDao" class="alb.springlearning.impl.UserDaoImpl">
            <property name="username" value="zhangsan"/>
            <property name="age" value="20"/>
            <property name="strList">
                <list>
                    <value>aaa</value>
                    <value>bbb</value>
                    <value>ccc</value>
                </list>
            </property>
            <property name="userMap">
                <map>
                    <entry key="user1" value-ref="user1"></entry>
                    <entry key="user2" value-ref="user2"></entry>
                </map>
            </property>
            <property name="properties">
                <props>
                    <prop key="p1">ppt1</prop>
                    <prop key="p2">ppt2</prop>
                    <prop key="p3">ppt3</prop>
                </props>
            </property>
        </bean>
    
        <!--单例-->
    
        <bean id="userService" class="alb.springlearning.service.impl.UserServiceImpl">
            <property name="userDao" ref="userDao"></property>
        </bean>
        <!--上述代码实现的功能就是将UserDao通过set方法将其注入到userService中-->
        <bean id="user1" class="alb.springlearning.dao.User">
            <property name="username" value="tom"/>
            <property name="addr" value="wuhu"/>
        </bean>
        <bean id="user2" class="alb.springlearning.dao.User">
            <property name="username" value="jack"/>
            <property name="addr" value="hefei"/>
        </bean>
    </beans>
    

引入其他配置文件

在实际开发中,经常由很多的配置文件,业务层由业务层的配置文件,数据层由数据层的配置文件,每次获取对象都要加载不同的配置文件,非常的麻烦,其不便于维护。因此,就可以将其他的配置文件都引入到同一个配置文件中,在后续使用的时候,只需要统一加载一个配置文件就行。

    <import resource="applicationContext-Dao.xml"></import>
    <import resource="applicationContext-Service.xml"></import>

Spring重点配置

< bean >标签:

id属性:在容器中Bean实例的唯一标识,不允许重复

class属性:要实例化的Bean的全限定名

scope属性:Bean的作用范围哦,常用是singleton(默认)和prototype

< property >标签:属性注入

    name属性:属性名称

    value属性:注入的普通属性值

    ref属性:注入的对象引用值

‘ < list >标签

    < map >标签

    < properties >标签

< constructor-arg>标签

< import >标签:导入其他的Spring的分文件

Spring相关API

ApplicationContext的继承体系

applicationContext:接口类型,代表应用上下文,可以通过其实例获得Spring容器中的Bean对象

ApplicationContext的实现类

  1. ClassPathXmlApplicationContext :从类的根路径下加载配置文件,推荐使用这种

  2. FileSystemXmlApplicationContext:从磁盘文件上加载配置文件,配置文件可以在磁盘的任意位置

  3. AnnotationConfigApplicationContext:当使用注解配置容器的时候,需要使用此类来创建spring容器,用来读取注解

  • getBean()方法的两种使用方式

    UserService userService = (UserService) app.getBean("userService");
    
    UserService userService=app.getBean(UserService.class)
    

Spring注解开发

配置数据源

数据源的作用:

  • 数据源是为提高程序性能出现的、

  • 事先实例化数据源,初始化部分连接资源

  • 使用链接资源时从数据源获取

  • 使用完毕后将链接资源归还给数据源

C3P0配置数据源

ComboPooledDataSource dataSource=new ComboPooledDataSource();   //创建数据源
        Connection connection = dataSource.getConnection();
        System.out.println(connection);
        connection.close();

Druid配置数据源

所有的数据库连接的配置文件,理论上也是可以放进applicationConterxt.xml即Spring容器中进行配置的。

但是在实际开发中,Spring 容器最好只负责管理Bean对象,而数据库连接的配置文件不能放在applicationContext.xml中。

所以需要在spring容器中对properties文件进行内容抽取

对properties文件进行内容抽取的步骤:

  • 引入命名空间

    <?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:property-placeholder location="classpath:druid.properties"></context:property-placeholder>

    <!--配置数据源-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${driverClassName}"></property>
        <property name="jdbcUrl" value="${url}"></property>
        <property name="user" value="${username}"></property>
        <property name="password" value="${password}"></property>
    </bean>

注解开发

Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替xml配置文件能够简化配置,提高开发效率

Spring原始注解

注解说明
@Component使用在类上用于实例化Bean
@Controller使用在web层上用于实例化Bean
@Service使用在service层上用于实例化Bean
@Repository使用在dao层上用于实例化Bean
@Autowired使用在字段上用于根据类型依赖注入
@Qualifier结合@Autowired一起使用用于根据名称进行依赖注入
@Resource相当于@Autowired+@Qualifier,按照名称进行注入
@Value注入普通属性值
@Scope标注Bean的作用范围
@PostConstruct使用在方法上标注该方法是Bean的初始化方法
@PreDestory使用在方法上标注该方法是Bean的销毁方法

使用注解开发的时候,需要在applicationContext.xml中配置组件扫描,作用是指定哪个包及其子包下的Bean需要进行扫描以便识别注解配置的类、字段和方法

AOP

AOP全称为Aspect Oriented Programming,面向切面编程,是用过图编译方式和运行动态代理实现程序功能的统一维护的一种技术。

利用AOP能够对业务逻辑各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高开发的效率。、

AOP的底层实现原理:

AOP底层通过Spring提供的动态代理技术实现,在运行期间,Spring通过攻台代理技术生成代理对象,代理对象方法执行时进行增强功能的介入,再去调用目标对象的方法,从而完成功能的增强。

动态代理技术

常用的动态代理技术有两种:

  • JDK代理:基于接口的动态代理技术

  • cglib代理:基于父类的动态代理技术

JDK代理

目标类接口

public interface TargetInterface {
    public void save();
}

目标类

public class Target implements TargetInterface{
    public void save(){
        System.out.println("save running");
    }
} 

动态代理代码

public class ProxyTest {
    public static void main(String[] args) {
        final Target target=new Target();

        //获得增强对象
        Advice advice=new Advice();


        //返回值就是动态生成的代理对象
        TargetInterface proxy= (TargetInterface) Proxy.newProxyInstance(
                target.getClass().getClassLoader(), //目标对象类加载器
                target.getClass().getInterfaces(),  //和目标对象相同的接口字节码对象数组
                new InvocationHandler() {
                    //调用代理对象的任何方法,实质上执行的都是invoke方法
                    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                        advice.before();
                        method.invoke(target,objects);
                        advice.After();
                        return null;
                    }
                }
        );
        proxy.save(); //调用代理对象的方法测试
    }
}
cglib动态代理

目标类

public class Target{
    public void save(){
        System.out.println("save running");
    }

}

动态代理代码

public class ProxyTest {
    public static void main(String[] args) {
        final Target target=new Target();

        final Advice advice=new Advice();

        //创建增强器
        Enhancer enhancer=new Enhancer();

        //设置父类
        enhancer.setSuperclass(alb.Aop.proxy_cglib.Target.class);

        //设置回调函数
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                advice.before();//执行前置
                Object invoke = method.invoke(target, args);//执行目标
                advice.After();//执行后置
                return invoke;
            }
        });
        //创建代理
        Target proxy= (Target) enhancer.create();
        //    测试
        proxy.save();//调用代理对象的方法测试
    }
}

AOP相关概念

Target(目标对象):代理的目标对象

Proxy(代理):一个类被AOP增强后,就产生一个结果代理类

JointPoint(连接点):所谓连接点是指那些被拦截到的点。在Spring中,这些点就是方法,因为spring只支持方法类型的连接点

PointCut(切入点):所谓切入点就是要对哪些JointPoint进行拦截的定义

Advice(通知/增强):所谓通知是拦截到JointPoint之后所要做的事就是通知

Aspect(切面): 是切入点和通知的结合

Weacing(织入):是指吧增强应用到目标对象来创建新的代理对象的过程,spring采用动态代理织入,而AspectJ采用编译期织入和类加载时织入

AOP开发明确事项

需要编写的内容

  • 编写核心业务代码(目标类的目标方法)

  • 编写切面类,切面类中有通知(增强方法功能)

  • 在配置文件中,配置织入关系

AOP技术实现的内容

Spring框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理记之,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。

AOP底层使用哪种代理方式

在spring中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式。

AOP总结

aop:面向切面编程

aop底层实现:jdk动态代理和cglib动态代理

重点概念:

Pointcut:切入点,被增强的方法

Advice:通知/增强,封装增强业务逻辑的方法

Aspect:切点+通知

Weaving:将切点与通知结合的过程

开发明确事项:

  • 哪些是切点(切点表达式配置)

  • 哪些是通知(切面类中的增强方法)

  • 将切点和通知进行织入配置

基于XML的AOP开发

开发步骤
  • 导入aop相关的坐标

    尽管spring中已经集成了aop,但是spring 也建议使用org.aspectj的aop包,并且新款spring也对该包做了兼容

    <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.8.13</version>
    
  • 创建目标接口和目标类

    public interface TargetInterface {
        public void save();
    }
    
    public class Target implements TargetInterface {
        public void save(){
            System.out.println("save running");
        }
    
    }
    
  • 创建切面类

    public class MyAspect {
        public void before(){
            System.out.println("前置增强");
        }
    }
    
  • 将目标类和切面类的对象的创建权交给spring

  • 在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"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                               http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <!--配置目标对象-->
        <bean id="target" class="alb.springaop.Spring_AOP.XML.Target"></bean>
    
        <!--配置切面对象-->
        <bean id="myAspect" class="alb.springaop.Spring_AOP.XML.MyAspect"></bean>
    
        <!--配置织入,告诉spring框架,哪些方法(切点)需要进行哪些增强-->
        <aop:config>
            <!--声明切面-->
            <aop:aspect ref="myAspect">
                <!--切面=切点+通知-->
                <aop:before method="before" pointcut="execution(public void alb.springaop.Spring_AOP.XML.Target.save())" ></aop:before>
            </aop:aspect>
        </aop:config>
    
    </beans>
    

    配置文件详解

    • 首先要添相应的命名空间

    • 然后将目标对象和切面对象全部交给spring容器来管理

    • 对于织入,则是aop开发中的重点。method属性的属性值是对应的切面文件中的增强方法,method的属性值就是该方法的方法名。pointCout是切点防范的ref名,实际上就是要进行功能增强的方法。另外,aop:before表示该方法是切面对切点进行的前置增强的方法

  • 测试代码

切点表达式的写法

表达式语法

execution(【修饰符】)返回值类型 报名.类名.方法名(参数)
  • 访问修饰符可以省略

  • 返回值类型、报名、类名、方法名可以使用星号*代表任意

  • 包名与类名之间一个点,代表当前包下的类,两个点…表示当前包及其子包下的类

  • 参数列表可以使用两个点…表示任意个数,任意类型的参数列表

通知的类型

名称标签说明
前置通知aop:before用于配置前置通知。指定增强的方法在切入点方法之前执行
后置通知aop:after_returning用于配置后置通知。指定增强的方法在切入点方法之后执行
环绕通知aop:around用于配置环绕通知。指定增强的方法在切入点方法之前和之后都执行
异常抛出通知aop:throwing用于配置异常跑出通知。指定的增强方法在出现异常时执行
最终通知aop:after用于配置的最终通知。无论增强方法执行是否有异常都会执行

其中环绕通知使用的方法中需要传递一个参数 ProceedingJoinPoint

对不同类型的通知进行测试,代码如下

环绕通知:

    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕前增强");
        Object proceed = pjp.proceed();
        System.out.println("环绕后增强");
        return proceed;
    }
<aop:around method="around"  pointcut="execution( public void alb.springaop.Spring_AOP.XML.Target.save())"></aop:around>

后置通知:

    public void afterreturning(){
        System.out.println("后置增强");
    }
<aop:after-returning method="afterreturning" pointcut="execution( public void alb.springaop.Spring_AOP.XML.Target.save())"></aop:after-returning>
切点表达式的抽取

使用切点表达式抽取的原因是:在进行大型项目的开发的时候,可能有不同的通知,但是这些不同的通知的切点表达式都是一样的。这样的话,如果需要对切点表达式进行修改,就需要将所有的通知意义修改。使用切点表达式抽取能够大大降低可能出现这种情况时的繁琐。

<aop:config>
        <!--声明切面-->
        <aop:aspect ref="myAspect">
            <aop:pointcut id="myPointcut" expression="execution( public void alb.springaop.Spring_AOP.XML.Target.save())"></aop:pointcut>
            <aop:after-returning method="afterreturning" pointcut-ref="myPointcut"></aop:after-returning>
        </aop:aspect>
    </aop:config>

基于注解AOP开发

开发步骤:

  1. 创建目标接口和目标类
public interface TargetInterface {
    public void save();
}
@Component("target")
public class Target implements TargetInterface {
    public void save(){
        System.out.println("save running");
    }

}
  1. 创建切面类
@Component("myAspect")
@Aspect //标注当前类是一个切面类
/*切面类*/
public class MyAspect {

    /*配置前置增强*/ /*配置织入关系*/
    @Before("execution( public void alb.springaop.Spring_AOP.Annotaion.Target.save())")
    public void before(){
        System.out.println("前置增强");
    }
    public void afterReturning(){
        System.out.println("后置增强");
    }
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕前增强");
        Object proceed = pjp.proceed();
        System.out.println("环绕后增强");
        return proceed;
    }

    public void afterreturning(){
        System.out.println("后置增强");
    }
}
  1. 将目标类和切面类的对象创建权交给spring

  2. 在切面类中使用注解配置织入关系

  3. 在配置文件中开启组件扫描和AOP的自动代理

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

    <!--配置组件扫描-->
    <context:component-scan base-package="alb.springaop.Spring_AOP.Annotaion"></context:component-scan>

    <!--配置自动代理-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
  1. 测试

注解通知的类型

名称注解说明
前置通知@Before用于配置前置通知,指定增强的方法在切入点方法之前执行
后置通知@AfterReturning用于配置后置通知,指定增强的方法在切入点方法之后执行
环绕通知@Around用于配置环绕通知,指定增强的方法在切入点方法之前和之后都执行
异常抛出通知@AfterThrowing用于配置异常抛出通知,指定增强的方法在出现异常时执行
最终通知@After用于配置最终通知,无论增强方法执行是否有异常都会执行

Spring JdbcTemplate

使用JdbcTemplate开发步骤主要如下:

  1. 创建数据源

  2. 创建模板对象

  3. 执行数据库操作

 ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/test?serverTimezone=GMT%2B8");
        dataSource.setUser("root");
        dataSource.setPassword("smt020528");

        JdbcTemplate template=new JdbcTemplate();
        template.setDataSource(dataSource);
        int row=template.update("insert into account values (?,?)","jack",123);
        System.out.println(row);

为提高开发效率,可以将JdbcTemplate的创建权交给Spring,将数据源DataSource的创建权利也交给Spring,在Spring容器内部将数据源DataSource注入到 JdbcTemplate模板对象中。

使用Template进行CRUD操作

query查询操作,Template的查询操作有一个特点,就是提供了自动封装返回结果的查询方法,返回查询结果的时候不需要进行手动封装

  • query(String sql, RowMapper rowMapper)

    上面的查询语句返回结果是一个List集合,用于查询多个对象

    RowMapper是一个专门用于进行封装的接口,但是在实际使用的时候是不可能直接使用这个接口进行封装的,需要使用它相关的实现类

    ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext-Jdbc.xml");
    JdbcTemplate template = (JdbcTemplate) app.getBean("jdbcTemplate");
    List<Account> query = template.query("select * from account", new BeanPropertyRowMapper<Account>(Account.class));
    System.out.println(query);
    
  • queryForObject(String sql,RowMapper rowMapper,Object args)

    上面的查询是针对查询单条记录的,其中Object args是查询语句中占位符需要传递的参数

    ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext-Jdbc.xml");
    JdbcTemplate template = (JdbcTemplate) app.getBean("jdbcTemplate");
    Account account = template.queryForObject("select * from account where username=?", new BeanPropertyRowMapper<Account>(Account.class),"justin");
    System.out.println(account);
    

事务控制

编程式事务控制

相关对象

PlatformTransactionManager : 该对象是一个接口,是spring的事务管理器,下面是接口中的方法

  • TransactionStatus getTransaction(TransactionDefination defination) 提交事务的状态信息

  • void commit(TransactionStatus status) 提交事务

  • void roolback(TransactionStatus status) 回滚事务

既然是一个接口,如果想要使用接口中的方法就一定要使用它的相关实现类,这个接口不需要开发者进行实现,spring已经提供了具体的实现类。并且,具体使用哪个实现类取决于Dao层使用的技术,如果dao层使用的是jdbc或mybatis时,使用org.springframework.jdbc.datasource.DataSourceTransactionManager,dao层使用的技术是hibernate时,使用org.springframework.orm.hibernate5.HibernateTransactionManager


TransactionDefination : 该对象是事务定义信息对象,下面是对象中的方法

  • int getIsolationLevel() 获取事务的隔离级别

    事务隔离级别:
    设置事务隔离级别,可以解决事务并发的问题, 如脏读、不可重复读和虚读

    • ISOLATION_DEFAULT

    • ISOLATION_READ_UNCOMMITED

      以上问题都不能解决

    • ISOLATION_READ_COMMITED

      能够解决脏读问题

    • ISOLATION_REPEATABLE_RTEAD

      能够解决不可重复读问题

    • ISOLATION_SERIALIZABLE

      串行化,能够解决上述的所有问题,但是效率很低,相当于锁表

  • int getPropogationBehavior() 获得事务的传播行为

    事务传播行为:事务传播行为解决的是业务层之间互相调用产生的事务冲突问题,下面是几种解决方法

    • REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务,加入到这个事务中。这个是不进行设置时的默认选择

    • SUPPORTS:支持当前事务,如果当前没有事务,就以非事务的方式运行‘

    • MANDATORY:使用当前的事务,如果的当前没有事务,就抛出异常

    • REQUERS_NEW:新建事务,如果当前在事务中,就将当前事务挂起

    • NOT_SUPPORTS:以非事务方式执行操作,如果当前存在事务,就将当前事务挂起

    • NEVER:以非事务方式运行,如果当前存在事务,抛出异常

  • int getTimaout() 获得超时时间

    超时时间:默认值是-1,没有超时限制。如果有,以秒为单位进行设置

  • boolean isReadOnly() 是否只读

    是否只读:建议查询时设置只读


TransactionStatus:该接口提供的是事务具体的运行状态,下面是接口中的方法

  • boolean hasSavepoint() 是否存储回滚点

  • boolean isCompleted() 事务是否完成

  • boolean isNewTransaction() 是否是新事务

  • boolean isRollbackOnly() 事务是否回滚

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值