目录

Spring介绍

Spring IOC

传统代码对象管理的弊端

实现过程

bean标签属性介绍

对象创建方式

工厂bean

bean的作用域

SpringBean的生命周期***

依赖注入

注解实现IOC

完全注解开发(JavaConfig)

Spring AOP

AOP的实现机制

JDK动态代理实现

CGlib代理

Spring中使用AOP

切入点方法的定义

获取切入点信息

使用AspectJ注解开发

Spring-JDBC 操作数据库

事务


Spring介绍

Spring是一个设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。Spring是一个分层的JavaSE/EE full-stack(一站式轻量级开源框架。

特点

1.方便解耦,简化开发

通过Spring提供的IoC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。有了Spring,用户不必再为单实例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。

2.AOP编程的支持

通过Spring提供的AOP功能,方便进行面向切面的编程,许多不容易用传统面向对象实现的功能可以通过AOP轻松应付。

3.声明式事务的支持

在Spring中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。

4.方便程序的测试

可以用非容器依赖的编程方式进行几乎所有的测试工作,在Spring里,测试不再是昂贵的操作,而是随手可做的事情。例如:Spring对Junit4支持,可以通过注解方便的测试Spring程序。

5.方便集成各种优秀框架

Spring不排斥各种优秀的开源框架,相反,Spring可以降低各种框架的使用难度,Spring提供了对各种优秀框架(如Struts,Hibernate、Hessian、Quartz)等的直接支持。

6.降低Java EE API的使用难度

组织结构

ORM- object relation mapping

OXM-Object xml mapping

JMS - Java消息服务(Java Message Service ,JMS)

WebSocket protocol 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-duplex)。一开始的握手需要借助HTTP请求完成。Socket是传输控制层协议,WebSocket是应用层协议。

Portlet是一种Web组件-就像servlets-是专为将合成页面里的内容聚集在一起而设计的。通常请求一个portal页面会引发多个portlets被调用。每个portlet都会生成标记段,并与别的portlets生成的标记段组合在一起嵌入到portal页面的标记内

spring全家桶:spring,Spring Data、Spring MVC、Spring Boot、Spring Cloud(微服务)

Spring核心模块

- spring-core:依赖注入IOC与DI的最基本实现

- spring-beans:Bean工厂与bean的装配

- spring-context:spring的context上下文即IoC容器

- spring-context-support

- spring-expression:spring表达式语言

Spring IOC

IOC是 Inverse of Control 的简写,意思是控制反转。是降低对象之间的耦合关系的设计思想。就是将对象统一管理,统一分配

传统代码对象管理的弊端

传统的调用方式时service层调用dao层,但是当我们的需求发生改变的时候,我们需要可能需要在写一个dao的实现类,然后再改变service的继承关系。但是这种改变源代码的方式不利于测试。我们可以用一种方式,就是把所有的对象提取出来,让一个容器来统一的管理。

 

实现过程

1、添加jar包

<!-- Spring的核心工具包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<!--在基础IOC功能上提供扩展服务,还提供许多企业级服务的支持,有邮件服务、 任务调度、远程访问、缓存以及多种视图层框架的支持-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<!-- Spring IOC的基础实现,包含访问配置文件、创建和管理bean等 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<!-- Spring context的扩展支持,用于MVC方面 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<!-- Spring表达式语言 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>

2、创建配置文件 applicationContext.xml (放在resource下面)

<?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">
</beans>

3、在配置文件中创建对象

<bean id="对象名" class="类的完整路径">
    <property name="属性名" ref="对象的id值"></property>
</bean>

4、加载配置文件,获得对象

ApplicationContext app=new ClassPathXmlApplicationContext("spring.xml");
Users users=(Users)app.getBean("u1");

举例:

模拟一个传统Service调用dao的过程

这里我们设计两个对象的调用过程, 我们可以把这两个对象写到配置文件中

首先new 两个对象

因为在UserServiceImpl中有个UserDao的属性

最后再在从配置文件中得到已经创建好的对象

注意:给属性赋值的时候,系统可以调用set方法,但是通过测试类得到属性的时候,只能调用配置文件

bean标签属性介绍

单列:每次拿到的对象都是同一个

对象创建方式

1、无参构造

2、有参构造

3、静态方法创建对象

4、非静态方法

工厂bean

spring有两种类型的bean,一种是普通的bean(和上面一样),另一种是工厂bean(FactoryBean)

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

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

实现步骤:

(1)创建类,让类实现FactoryBean接口

(2)实现接口方法,在实现的方法中定义bean的类型

bean的作用域

设置bean的实例是单例还是多例

单例(默认)
<bean id="myBean" class="com.vv.bean.MyBean" scope="singleton"></bean>
多例
<bean id="myBean" class="com.vv.bean.MyBean" scope="prototype"></bean>

设置指为singleton时:加载配置文件的时候就会创建对象

设置值为prototype时:在调用getBean方法的时候才创建多实例对象

SpringBean的生命周期***

1)根据配置文件调用 Bean 构造方法或工厂方法实例化 Bean。

2)利用依赖注入(DI)完成 Bean 中属性值的配置注入。

3)如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName() 方法传入当前Bean 的 id 值。

4)如果 Bean 实现了 BeanFactoryAware 接口,则 Spring 调用 setBeanFactory() 方法传入当前工厂实例的引用。

5)如果 Bean 实现了 ApplicationContextAware 接口,则 Spring 调用 setApplicationContext() 方法传入当前 ApplicationContext 实例的引用。

6)如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的预初始化方postProcessBeforeInitialzation() 对Bean 进行加工操作,此处非常重要,Spring 的 AOP 就是利用它实现的。

7)如果 Bean 实现了 InitializingBean 接口,则 Spring 将调用 afterPropertiesSet() 方法。初始化bean的时候执行,可以针对某个具体的bean进行配置。afterPropertiesSet 必须实现 InitializingBean接口。实现 InitializingBean接口必须实现afterPropertiesSet方法。

8)如果在配置文件中通过 init-method 属性指定了初始化方法,则调用该初始化方法。

9)如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的初始化方法postProcessAfterInitialization()。此时,Bean 已经可以被应用系统使用了。

10)如果在中指定了该 Bean 的作用范围为 scope="singleton",则将该 Bean 放入 Spring IoC 的缓存池中,将触发 Spring 对该 Bean 的生命周期管理;如果在中指定了该 Bean 的作用范围为scope="prototype",则将该 Bean 交给调用者,调用者管理该 Bean 的生命周期,Spring 不再管理该Bean。

11)如果 Bean 实现了 DisposableBean 接口,则 Spring 会调用 destory() 方法将 Spring 中的 Bean销毁;如果在配置文件中通过 destory-method 属性指定了 Bean 的销毁方法,则 Spring 将调用该方法对 Bean 进行销毁。

依赖注入

DI是Dependency Injection的缩写,意思是依赖注入,说的是创建对象实例时,同时为这个对象注入它所依赖的属性

分类:一种是调用属性的set方法赋值,第二种使用构造方法赋值

1、set注入指(调用属性的set方法)

2、构造方法注入

spel spring表达式

c、p命名空间

- 基本类型值: p:属性名="值"
- 引用类型值: P:属性名-ref="beanid"

3、复杂类型的注入(Object[],list,set,map,Properties类型)

    <bean id="t1" class="com.vv.bean.Teacher">
<property name="objects">
<list>
<value>vv</value><!--字符串-->
<value>19</value><!--数-->
<ref bean="u1"></ref><!--引用类型-->
</list>
</property>
<property name="list">
<list>
<value>xx</value><!--字符串-->
<value>19</value><!--数-->
</list>
</property>
<property name="set">
<set>
<value>77</value><!--字符串-->
<value>19</value><!--数-->
<ref bean="u1"></ref><!--引用类型-->
</set>
</property>
<property name="map">
<map>
<entry key="班长" value="77"></entry>
<entry key="user" value-ref="u1"></entry><!--引用类型-->
</map>
</property>
<property name="properties">
<props>
<prop key="username">root</prop>
<prop key="password">123</prop>
</props>
</property>
</bean>

4、自动装配(注入):Spring会在上下文中自动寻找,并自动给bean装配属性

autowire:

no 不自动装配(默认值)

byName 属性名=id ,调取set方法赋值

byType 属性的类型和id对象的类型相同,当找到多个同类型的对象时报错,调取set方法赋值(保证id唯一)

constructor 构造方法的参数类型和id对象的类型相同,当没有找到时报错。调取构造方法赋值(保证class唯一)

注解实现IOC

1、配置文件中添加约束

xmlns:context="http://www.springframework.org/schema/context"

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context.xsd

2、配置注解扫描:指定扫描包下所有类中的注解,扫描包时,会扫描包所有的子孙包

<!--扫描包设置-->
<context:component-scan base-package="com.vv"></context:component-scan>

3、注解

(1)添加到类名上

@Component("对象名") :将某个类注册到Sping中,装配Bean
componet的衍生注解:
@Service("对象名") // service层
@Controller("对象名") // controller层
@Repository("对象名") // dao层 @Scope(scopeName="singleton") //单例对象
@Scope(scopeName="prototype") //多例对象

(2)添加到属性

@Value("属性值")
private String name; @Autowired//默认使用byType,如果通过Repository注解了两个相同类型的对象就会报错
@Qualifier("uDao")//这样就可以指定对应的对象了
private UserDao userDao; //@Resource(name="对象名") == @Autowired + @Qualifier("name")
@Resource(name="uDao")
private UserDao userDao; 注意:通过注解配置,对象里面的属性就不需要有set方法了

可能会没有Resource这个注解,需要加入依赖包

<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.1</version>
</dependency>

(3)添加到方法上

@PostConstruct //等价于init-method属性
public void init(){
System.out.println("初始化方法");
} @PreDestroy //等价于destroy-method属性
public void destroy(){
System.out.println("销毁方法");
}

完全注解开发(JavaConfig)

1、创建配置类,替代xml配置文件

@Configuration//作为配置类,替代xml配置文件
@ComponentScan(basePackages = {"com.vv"})//开启组件扫描
public class SpringConfig { }

2、加载配置类

ApplicationContext app = new AnnotationConfigApplicationContext(SpringConfig.class);

此方法在springboot中使用

Spring AOP

AOP(Aspect Oriented Programming)即面向切面编程。即在不改变原程序的基础上为代码段增加新的功能。应用在权限认证、日志、事务

AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

想象下面的场景,开发中在多个模块间有某段重复的代码,我们通常是怎么处理的?显然,没有人会靠“复制粘贴”吧。在传统的面向过程编程中,我们也会将这段代码,抽象成一个方法,然后在需要的地方分别调用这个方法,这样当这段代码需要修改时,我们只需要改变这个方法就可以了。然而需求总是变化的,有一天,新增了一个需求,需要再多出做修改,我们需要再抽象出一个方法,然后再在需要的地方分别调用这个方法,又或者我们不需要这个方法了,我们还是得删除掉每一处调用该方法的地方。实际上涉及到多个地方具有相同的修改的问题我们都可以通过 AOP 来解决。

AOP的实现机制

- JDK 的动态代理:针对实现了接口的类产生代理。InvocationHandler接口

- CGlib 的动态代理:针对没有实现接口的类产生代理,应用的是底层的字节码增强的技术 生成当前类的子类对象,MethodInterceptor接口

JDK动态代理实现

创建接口实现类的代理对象,增强方法

//代理类
public class dai implements InvocationHandler { private UserService service;//目标对象 public dai(UserService service) {
this.service = service;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//本方法中的其他输出输入增强
//proxy 代理方法被调用的代理实例
System.out.println("日志开始");
//调取真实的方法
Object invoke = method.invoke(service, args);
System.out.println("日志结束");
return invoke;
}
}
public class Test {
public static void main(String[] args) {
UserService service = new UserServiceImpl(); dai d = new dai(service);
//生成代理对象,这里不能转换成一个实际的类,必须是接口类型
UserService us = (UserService) Proxy.newProxyInstance(service.getClass().getClassLoader(), service.getClass().getInterfaces(), d);
us.insert(new User());
}
}

CGlib代理

使用JDK创建代理有一个限制,它只能为接口创建代理实例.这一点可以从Proxy的接口方法 newProxyInstance(ClassLoader loader,Class [] interfaces,InvocarionHandler h)中看的很清楚,第二个入参 interfaces就是需要代理实例实现的接口列表.

CGLib采用底层的字节码技术,可以为一个类创建子类,在子类中完成类的增强

1、添加依赖包

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

2、创建个工具类(代理器)

public class CglibProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("日志开始");
Object o1 = methodProxy.invokeSuper(o, objects);
System.out.println("日志结束");
return o1;
}
}

3、测试

public class Test {
public static void main(String[] args) {
Try t = new Try();
//创建代理对象
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(t.getClass());
enhancer.setCallback(new CglibProxy());
Try t2 = (Try) enhancer.create();
t2.test();
}
}

两种代理方式的区别:

1、jdk动态代理生成的代理类和委托类实现了相同的接口;

2、cglib动态代理中生成的字节码更加复杂,生成的代理类是委托类的子类,且不能处理被final关键字修饰的方法;

3、jdk采用反射机制调用委托类的方法,cglib采用类似索引的方式直接调用委托类方法;

注:spring同时使用了这两种方式,底层会自行判断应该使用哪种

Spring中使用AOP

AOP中的术语

(1)连接点:类中可以被增强的方法

(2)切点:实际被真正增强的方法

(3)增强(通知):增强逻辑的部分(日志处理、权限判断)

(4)切面:把增强运用到切点的过程

步骤

1、添加依赖包

<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>

2、创建增强类(本质上就是一个普通类)

public class MyAop {
//前置增强-调用目标方法之前执行
public void before(){
System.out.println("日志开始");
} //后置增强-调用目标方法之后执行
public void after(){
System.out.println("日志开始");
} /**
* @param joinPoint 获取切入点
*/
public void around(ProceedingJoinPoint joinPoint){
System.out.println("环绕开始");
try {
joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("环绕结束");
} //异常增强
public void ex(){
System.out.println("异常增强");
} //最终增强
public void end(){
System.out.println("最终增强");
}
}

3、添加aop命名空间

xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd

3、配置文件

增强类型:

前置增强:目标方法运行之前调用 aop:before

后置增强(如果出现异常不会调用):在目标方法运行之后调用 aop:after-returning

环绕增强:在目标方法之前和之后都调用 aop:around

异常增强:程序出现异常时执行(要求:程序代码中不要处理异常) aop:after-throwing

最终增强(无论是否出现 异常都会调用):在目标方法运行之后调用 aop:after

<bean id="udao" class="com.vv.dao.impl.UserDaoImpl"></bean>
<bean id="uService" class="com.vv.service.impl.UserServiceImpl" >
<property name="userDao" ref="udao"></property>
</bean> <!--创建增强类对象-->
<bean id="myaop" class="com.vv.util.MyAop"></bean>
<!--建立增强类和目标方法的关系-->
<aop:config>
<aop:pointcut id="mypc" expression="execution(void com.vv.service.UserService.insert())"/>
<aop:aspect ref="myaop">
<!--前置增强-->
<aop:before method="before" pointcut-ref="mypc"></aop:before>
<!--后置增强-->
<aop:after method="after" pointcut-ref="mypc"></aop:after>
<!--环绕增强-->
<aop:around method="around" pointcut-ref="mypc"></aop:around>
<!--异常增强-->
<aop:after-throwing method="ex" pointcut-ref="mypc"></aop:after-throwing>
<!--最终增强-->
<aop:after-returning method="end" pointcut-ref="mypc"></aop:after-returning>
</aop:aspect>
</aop:config>

4、测试

ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService service = app.getBean("uService", UserService.class);
service.insert();

注意:(1)环绕增强需要使用ProceedingJoinPoint 作为参数(2)注意标签顺序

另一种方式

特殊的前置增强-->Advisor前置增强实现

(1)创建增强类,要求该类实现MethodBeforeAdvice接口

(2)设置配置文件,定义增强和切入点的关系

public class agency implements MethodBeforeAdvice {
/**
* @param method 要执行目标对象的方法
* @param objects 参数
* @param o 目标对象
*/
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println(o.getClass().getName()+" 的 "+method.getName()+" 被执行了");
}
}
<bean id="userDao" class="com.vv.dao.Impl.UserDaoImpl"></bean>
<bean id="agency" class="com.vv.agency"></bean>
<aop:config>
<!--切入点-->
<aop:pointcut id="pointcut" expression="execution(* com.vv.dao.Impl.*.*(..))"/>
<aop:advisor advice-ref="agency" pointcut-ref="pointcut"/>
</aop:config>

切入点方法的定义

表达式匹配规则举例:

1、public * addUser(com.pb.entity.User):“*”表示匹配所有类型的返回值。

public int addUser(User u);
public String addUser(User u);

2、public void *(com.pb.entity.User):“*”表示匹配所有方法名

public void selectUser(User u);
public void a(User u);

3、public void addUser (..):“..”表示匹配所有参数个数和类型。

public void addUser(int a);
public void addUser(int b,int c);

4、com.pb.service.*.*(..):匹配com.pb.service 包下所有类的所有方法。

public void com.pb.service.A.a();
public String com.pb.service.B.a();

5、* com.pb.service..*(..):匹配com.pb.service 包及子包下所有类的所有方法

获取切入点信息

通过JoinPoint对象获取信息

public void before(JoinPoint joinPoint){
System.out.println("日志开始");
System.out.println(new Date());
System.out.println("对象信息:"+joinPoint.getTarget().getClass().getSimpleName());
System.out.println("方法信息:"+joinPoint.getSignature());
System.out.println("参数信息:"+joinPoint.getArgs());
}

使用AspectJ注解开发

1、启动扫描Spring注解的包,启动aspectJ的注解方式

<!--扫描Spring注解包-->
<context:component-scan base-package="com.vv"></context:component-scan>
<!--开启aspectj,生成代理对象-->
<aop:aspectj-autoproxy/>

2、增强类使用@Componet注解,添加@Aspect

3、在增强类中定义切点,指明要修饰的方法

@Component
@Aspect //生成代理对象
public class MyAop { //定义切点,由于注解必须修饰方法,所以这里要定义一个空方法
@Pointcut("execution(* com.vv.service.*.*(..))")
public void p(){} //前置增强-调用目标方法之前执行
@Before("p()")
public void before(){
System.out.println("日志开始");
} //后置增强-调用目标方法之后执行
@AfterReturning("p()")
public void after(){
System.out.println("日志结束");
} /**
* @param joinPoint 获取切入点
*/
@Around("p()")
public void around(ProceedingJoinPoint joinPoint){
System.out.println("环绕开始");
try {
joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("环绕结束");
} //异常增强
@AfterThrowing("p()")
public void ex(){
System.out.println("异常增强");
} //最终增强
@After("p()")
public void end(){
System.out.println("最终增强");
}
}

或者直接这样使用

注解方式中注解的顺序

Spring-JDBC 操作数据库

导入依赖

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>

原始的使用方式:

public class demo1 {
public static void main(String[] args) throws PropertyVetoException {
//1.创建c3p0链接池
ComboPooledDataSource dataSource=new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/try");
dataSource.setUser("root");
dataSource.setPassword("");
//创建jdbcTemplate对象
JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource);
//创建sql语句
String sql="insert into users values (?,?,?);";
jdbcTemplate.update(sql, 4, "vv", "321");
}
}

Spring管理jdbcTemplate

让dao实现类继承JdbcDaoSupport,父类中可以提供jdbcTemplate对象

然后修改配置文件,在配置文件中配置数据源信息

<bean id="ds" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/try"/>
<property name="user" value="root"/>
<property name="password" value=""/>
</bean> <bean id="userDao" class="com.vv.dao.Impl.UserDaoImpl">
<property name="dataSource" ref="ds"></property>
</bean>

dao实现类

public class UserDaoImpl extends JdbcDaoSupport implements UserDao {
@Override
public int insert(User user) {
String sql = "insert into users values (?,?,?);";
int usid = user.getUsid();
String username = user.getUsername();
String password = user.getPassword();
int update = getJdbcTemplate().update(sql, usid, username, password);
return update;
}
}

之前我们是吧数据库的配置信息放在properties文件中,我们这里也可以用同样的方式

jdbc.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/try
username=root
password=

配置文件

<context:property-placeholder location="classpath:jdbc.properties" system-properties-mode="FALLBACK"></context:property-placeholder>

<bean id="ds" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${driver}"/>
<property name="jdbcUrl" value="${url}"/>
<property name="user" value="${username}"/><!--这里的username默认调用的系统的username,在上面添加system-properties-mode="FALLBACK-->
<property name="password" value="${password}"/>
</bean> <bean id="userDao" class="com.vv.dao.Impl.UserDaoImpl">
<property name="dataSource" ref="ds"></property>
</bean>

CRUD操作操作

public class UserDaoImpl extends JdbcDaoSupport implements UserDao {
@Override
public int insert(User user) {
String sql = "insert into users values (?,?,?);";
int usid = user.getUsid();
String username = user.getUsername();
String password = user.getPassword();
int update = getJdbcTemplate().update(sql, usid, username, password);
return update;
} @Override
public User findbyid(int id) {
String sql ="select * from users where usid = ?";
User user = getJdbcTemplate().queryForObject(sql, new Object[]{id}, new RowMapper<User>() {
@Override
public User mapRow(ResultSet resultSet, int i) throws SQLException {
User user = new User();
user.setUsid(resultSet.getInt("usid"));
user.setUsername(resultSet.getString("username"));
user.setPassword(resultSet.getString("password"));
return user;
}
});
return user;
} @Override
public List<User> findAll() {
String sql = "select * from users";
List<User> list = getJdbcTemplate().query(sql, new RowMapper<User>() {
@Override
public User mapRow(ResultSet resultSet, int i) throws SQLException {
User user = new User();
user.setUsid(resultSet.getInt("usid"));
user.setUsername(resultSet.getString("username"));
user.setPassword(resultSet.getString("password"));
return user;
}
});
return list;
} @Override
public int update(int id, User user) {
String sql = "update users set username = ?, password = ? where usid =?";
int update = getJdbcTemplate().update(sql,user.getUsername(),user.getPassword(),id);
return update;
} @Override
public int delete(int id) {
String sql = "delete from users where usid = ?";
int update = getJdbcTemplate().update(sql, id);
return update;
}
}

事务

通过sql将逻辑相关的一组操作绑定在一起,以便服务器 保持数据的完整性(准确性)。

事务通常是以begin transaction开始,以commit或rollback结束。

事务执行的流程:开启事务->执行insert,update,delete->commit/rollback

事务的特性ACID

1 - 原子性(atomicity)

事务是数据库的逻辑工作单位,而且是必须是原子工作单位,对于其数据修改,要么全部执行,要么全部不执行。

2、一致性(consistency)

事务在完成时,必须是所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。

3、隔离性(isolation)

一个事务的执行不能被其他事务所影响。企业级的数据库每一秒钟都可能应付成千上万的并发访问,因而带来了并发控制的问题。

4、持久性(durability)

一个事务一旦提交,事务的操作便永久性的保存在DB中。即使此时再执行回滚操作也不能撤消所做的更改

事务传播行为propagation

多事务方法(对数据库数据进行改变)之间进行调用,这个过程中事务是如何进行管理的。

当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。规定了事务方法和事务方法发生嵌套调用时事务如何进行传播例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。

七种传播行为*

事务传播行为失效的情况

spring事务是基于代理来实现的,所以:

(1)private、fifinal、static 方法无法被代理,所以添加事务无效

(2)当绕过代理对象, 直接调用添加事务管理的方法时, 事务管理将无法生效。比如直接new出的对象。

(3)在同一个类下,有2个方法,A、B,A没有事务,B有事务,但是A调用B时,方法B被标记的事务无效。 究其原因,因为此类的调用对象为代理对象,代理方法A调用真正的被代理方法A后,在被代理方法A中才会去调用方法B,此时this对象为被代理的对象,所以是不会通知到代理对象,也就变成了第二种情况,绕过了代理对象。所以无事务隔离级别

事务的隔离级别

脏读:读取到一个未提交事务的数据,若事务回滚可能导致数据不一致

不可重复读:一个未提交的事务两次读取的数据不一致

幻读:一个未提交的事务读取到另一个提交事务添加数据

1. Serializable(串行化):可避免脏读、不可重复读,幻读情况的发生。

2. Repeatable read(可重复读):可避免脏读、不可重复读情况的发生。

3. Read committed(读已提交):可避免脏读情况发生。

4. Read uncommitted(读未提交):最低级别,以上情况均无法保证。

事务操作(Spring事务管理

一般添加到JavaEE三层结构里面的Service层

有两种事务管理操作:编程式事务管理(在代码前后添加代码,不常用)和声明式事务管理(常用)

声明式事务管理(底层使用到了AOP):

1、基于注解

修改配置文件

<!--创建事务管理器-->
<bean id="manager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="ds"/>
</bean>
<!--开启事务注解-->
<tx:annotation-driven transaction-manager="manager"></tx:annotation-driven>

添加注解

注解中可配置的参数

propagation:事务传播行为(默认Propagation.REQUIRED)

isolation:隔离级别

timeout:超时时间(在一定时间不提交就会回滚,默认-1不超速)

readOnly:是否只读(默认false,可以进行增伤改查,true:只能查询)

rollbackFor:回滚

norollbackFor:不回滚

2、基于XML

<!--创建事务管理器--><!--这里id好像必须写成transactionManager-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="ds"/>
</bean> <!--配置增强-->
<tx:advice id="txAdvice">
<tx:attributes>
<!--哪种规则的方法添加事务-->
<tx:method name="insert*" propagation="REQUIRED"/><!--以insert开头的方法-->
<tx:method name="update*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!--配置切入点和切面-->
<aop:config>
<!--切入点-->
<aop:pointcut id="mypoint" expression="execution(* com.vv.service.*.*(..))"/>
<!--切面 把事务通知配置到切点上-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="mypoint"></aop:advisor>
</aop:config>

Spring(IOC、AOP和事务)的更多相关文章

  1. spring ioc aop 原理

    spring ioc aop 原理 spring ioc aop 的原理 spring的IoC容器是spring的核心,spring AOP是spring框架的重要组成部分. 在传统的程序设计中,当调 ...

  2. Spring基于AOP的事务管理

                                  Spring基于AOP的事务管理 事务 事务是一系列动作,这一系列动作综合在一起组成一个完整的工作单元,如果有任何一个动作执行失败,那么事务 ...

  3. Spring IOC AOP的原理 如果让你自己设计IOC,AOP如何处理(百度)

    百度的面试官问,如果让你自己设计一个IOC,和AOP,如何设计, 我把IOC的过程答出来了,但是明显不对, (1) IOC 利用了反射,自己有个id,classtype,hashmap,所有的功能都在 ...

  4. Spring IOC + AOP 的实现

    Spring思想很不错,尽量减少侵入式编程.现在了解到的Spring提供的功能有,DI,IOC,数据库操作,AOP,MVC.针对DI,AOP写了一些小DEMO PS:AOP真的很棒 代码参考:< ...

  5. spring Ioc Aop整合

    之前用DWP项目做spring的IOC,xml总是提示有问题,之后改用maven通过. 之后将这一块的内容补充. 仔细考虑一下spring 的IOC是无处不在的,演示Aop也需要依赖spring的IO ...

  6. spring ioc aop 理解

    OC,依赖倒置的意思,所谓依赖,从程序的角度看,就是比如A要调用B的方法,那么A就依赖于B,反正A要用到B,则A依赖于B.所谓倒置,你必须理解如果不倒置,会怎么着,因为A必须要有B,才可以调用B,如果 ...

  7. Spring 的 AOP 进行事务管理的一些问题

    AspectJ AOP事务属性的配置(隔离级别.传播行为等): <tx:advice id="myAdvice" transaction-manager="mtTx ...

  8. Spring IOC/ AOP 笔记

    扫描 Bean 以下主要是使用基于注解方式配置 组件扫描(一般用于自己写的类) 添加 @Component 注解,被扫描到后自动作为 Bean 组件 @ComponentScan 扫描配置的位置,将添 ...

  9. spring IOC DI AOP MVC 事务, mybatis 源码解读

    demo https://gitee.com/easybao/aop.git spring DI运行时序 AbstractApplicationContext类的 refresh()方法 1: pre ...

随机推荐

  1. 关于一些视图的基本操作(结合YGGL.sql)

    二.操作题 1.创建视图emp_view2,包含员工编号,姓名,所在部门名称和收入. mysql> create or replace view emp_view2 -> as -> ...

  2. Spring Boot 应用使用spring session+redis启用分布式session后,如何在配置文件里设置应用的cookiename、session超时时间、redis存储的namespace

    现状 项目在使用Spring Cloud搭建微服务框架,其中分布式session采用spring session+redis 模式 需求 希望可以在配置文件(application.yml)里设置应用 ...

  3. Go中由WaitGroup引发对内存对齐思考

    转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com 本文使用的go的源码时14.4 WaitGroup使用大家都会,但是其中是怎么实现的我们 ...

  4. 【Spring】Spring的数据库开发 - 2、Spring JdbcTemplate的常用方法(execute、update、query)

    Spring JdbcTemplate的常用方法 文章目录 Spring JdbcTemplate的常用方法 execute() update() query() 简单记录-Java EE企业级应用开 ...

  5. 【Linux】查看系统僵尸进程

    ps -ef|grep -v grep|grep defunct 如果这个有显示内容的话,可以手动将进程kill掉即可 ---------------------------------------- ...

  6. Sentry(v20.12.1) K8S 云原生架构探索,JavaScript 性能监控之管理 Transactions

    系列 Sentry-Go SDK 中文实践指南 一起来刷 Sentry For Go 官方文档之 Enriching Events Snuba:Sentry 新的搜索基础设施(基于 ClickHous ...

  7. [USACO2011 Feb] Cow Line

    原题链接https://www.lydsy.com/JudgeOnline/problem.php?id=3301 康拓展开和逆展开的模板题. #include<iostream> #in ...

  8. ElasticSearch Python 基本操作

    创建索引 from elasticsearch import Elasticsearch es = Elasticsearch('192.168.149.96:9200') mappings = { ...

  9. uni-app开发经验分享十三:实现手机扫描二维码并跳转全过程

    最近使用 uni-app 开发 app ,需要实现一个调起手机摄像头扫描二维码功能,官网API文档给出了这样一个demo: // 允许从相机和相册扫码 uni.scanCode({ success: ...

  10. 说说C# 8.0 新增功能Index和Range的^0是什么?

    前言 在<C# 8.0 中使用 Index 和 Range>这篇中有人提出^0是什么意思?处于好奇就去试了,结果抛出异常.查看官方文档说^0索引与 sequence[sequence.Le ...