访问数据库基本是所有java web项目必备的,不论是oracle、mysql,或者是nosql,肯定需要和数据库打交道。一开始学java的时候,肯定是以jdbc为基础,如下:

private static int insert(Student student) {
String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/samp_db";
String username = "root";
String password = "";
Connection conn = null;
int i = 0;
String sql = "insert into students (Name,Sex,Age) values(?,?,?)";
PreparedStatement pstmt;
try {
Class.forName(driver); //classLoader,加载对应驱动
conn = (Connection) DriverManager.getConnection(url, username, password);
pstmt = (PreparedStatement) conn.prepareStatement(sql);
pstmt.setString(1, student.getName());
pstmt.setString(2, student.getSex());
pstmt.setString(3, student.getAge());
i = pstmt.executeUpdate();
pstmt.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
} return i;
}

spring对dao层提供了不同的模板类,主要如下;

主要机制如下:

数据源

在spring中,数据连接是通过数据源获得的。数据源一般是由web应用服务器提供,spring中,通过jndi的方式获取,也可以直接在spring容器中配置,当然也可以通过代码的方式创建一个数据源。

1、dbcp数据源

jar包依赖:

commons-dbcp2-2.1.1.jar
commons-logging-1.2.jar
commons-pool2-2.4.2.jar

配置如下:

2、c3p0数据源

jar包依赖:

mchange-commons-java-0.2.11.jar
c3p0-0.9.5.2.jar

配置如下:

3、jndi数据源

如果应用配置在高性能的应用服务器上,那么可能希望使用应用服务器本身提供的数据源。应用服务器的数据源使用JNDI开放调用者使用,spring专门提供了引用jndi数据源的JndiObjectFactoryBean,配置如下:

另外spring为获取java ee资源提供了一个jee命名空间,通过jee可以有效的简化java ee资源的引用。利用jee命名空间引用jndi数据源的配置如下:

4、DriverManagerDataSource(spring提供)

 事务

针对事务,本人准备在后续数据库章节专门进行阐述,这里只要知道事务是为了保证一系列的操作要么同时成功,要么同时失败的机制。

jdbc事务操作:

在jdbc3.0之后,引入了savepoint的概念,流程如下;

spring对事务的支持

spring事务管理的亮点在于声明式事务管理,主要包括如下几个元素:

1、TransactionDefinition

定义了spring兼容的事务属性,包括事务隔离、事务传播、事务超时、只读状态等等。

2、TransactionStatus

代表一个事务的具体运行状态

3、PlatformTransactionManagerspring

提供的事务管理的对象

spring可以支持很多orm框架,例如mybatis、jpa、hibernate等,spring提供的事务管理类如下:

spring事务管理器实现类

1、spring jdbc、mybatis

基于数据源的connection访问数据库,所以可以使用DataSourceTransactionManager,配置如下:

DataSourceTransactionManager可以使用DataSource的connection对象的commit()、rollback()等方法来管理事务。

2、jpa

jpa通过javax.persistence.EntityTransaction来管理jpa事务。
其中EntityTransaction需要通过javax.persistence.EntityManager#getTransaction()获得,EntityManager则是由javax.persistence.EntityManagerFactory#createEntityManager()获取。

事务同步管理器

在spring中,jdbc的connection,hibernate的session等访问数据库的连接或会话对象统称为资源,这些资源在同一时刻是不能多线程共享的。那么如何解决呢?spring使用事务同步管理器(org.springframework.transaction.support.TransactionSynchronizationManager)使用ThreadLocal为不同事务线程提供了独立的资源副本,同时维护事务配置的属性和运行状态信息。

spring事务配置

1、xml配置方式

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
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-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">
<!-- 事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 传播行为 -->
<tx:method name="save*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<!-- 切面 -->
<aop:config>
<aop:advisor advice-ref="txAdvice"
pointcut="execution(* com.jeenotes.ssm.service.*.*(..))" />
</aop:config>
</beans>

不过这种方式一看就不方便,下面说说注解方式

2、基于注解配置(@Transactional)

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
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-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">
<!-- 事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 开启事务控制的注解支持,配置 Annotation 驱动,扫描@Transactional注解的类定义事务。proxy-target-class为true代表使用CGLIB类代理;false则代表使用的是jdk动态代理 -->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
</beans>
public class DefaultFooService implements FooService {

  public Foo getFoo(String fooName) {
// do something
} //方法上注解属性会覆盖类注解上的相同属性
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateFoo(Foo foo) {
// do something
}
}

@Transactional注解:

a、属性

b、作用范围

@Transactional注解可以应用于接口定义接口方法类定义类的public方法上。
但是不建议使用在接口中,主要是因为当proxy-target-class="true"时,接口的实现类将会工作在非事务环境下,所以spring建议在具体的类上使用@Transactional。

c、方法中使用@Transactional

@Transactional(readOnly = true)
public class DefaultFooService implements FooService { public Foo getFoo(String fooName) {
// do something
} // these settings have precedence for this method
//方法上注解属性会覆盖类注解上的相同属性
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateFoo(Foo foo) {
// do something
}
}

spring事务易错点

1、关于spring事务,经常会有一种错误的说法,就是一个事务方法不应该调用另一个事务方法,否则将产生两个事务。

事务的传播行为

spring中的默认事务传播行为是PROPAGATION_REQUIRED,因此当一个方法使用@Transactional修饰,调用另一个使用@Transactional修饰的方法,则这两个方法其实是工作在同一个事务当中。

2、多线程下的事务安全

web容器基本都是多线程的,即使开发者认为自己没有开启多线程,但其实整个web容器为了能够处理更多的请求,都是使用共享线程池的方式来处理请求。在spring应用中,大部分的bean都是单例的,因此倒不会出现线程安全问题。

但是dao层持有的都是connection对象,这个连接对象肯定是状态化的。spring的解决方式就是通过ThreadLocal将有状态的变量(connection等)本地线程化,实现线程安全。

结论:在相同线程中进行相互嵌套调用的事务方法工作在相同的事务中;如果这些相互嵌套调用的方法工作在不同的线程中,则不同线程下的事务方法工作在独立的事务中。

3、哪些方法实现不了spring aop事务

大家都知道aop的实现原理主要有jdk动态代理或者cglib,那么对于spring aop事务的实现,还是有一定的要求的:

  • 基于jdk动态代理的aop事务基于接口,所以要求方法必须是public修饰,并且不能使用static修饰;
  • 而基于cglib字节码动态代理的方案是通过扩展被增强类,动态创建其子类的方式进行aop增强,但是final、static、private修饰的方法都不能被子类覆盖,所以这些方法无法实施aop增强。

spring深入学习(五)-----spring dao、事务管理的更多相关文章

  1. spring框架学习笔记7:事务管理及案例

    Spring提供了一套管理项目中的事务的机制 以前写过一篇简单的介绍事务的随笔:http://www.cnblogs.com/xuyiqing/p/8430214.html 还有一篇Hibernate ...

  2. spring boot学习(6) SpringBoot 之事务管理

    两个操作要么同时成功,要么同时失败: 事务的一致性: 以前学ssh ssm都有事务管理service层通过applicationContext.xml配置,所有service方法都加上事务操作: 用来 ...

  3. Spring Boot学习——数据库操作及事务管理

    本文讲解使用Spring-Data-Jpa操作数据库. JPA定义了一系列对象持久化的标准. 一.在项目中使用Spring-Data-Jpa 1. 配置文件application.properties ...

  4. Spring+Mybatis+MySql+Maven 简单的事务管理案例

    利用Maven来管理项目中的JAR包,同时使用Spring在业务处理层进行事务管理.数据库使用MySq,数据处理层使用Spring和Mybatis结合. 本案例代码主要结构如图: 1.数据库脚本 -- ...

  5. Spring整合JMS(四)——事务管理

    原文链接:http://haohaoxuexi.iteye.com/blog/1983532 Spring提供了一个JmsTransactionManager用于对JMS ConnectionFact ...

  6. Spring整合JMS(四)——事务管理(转)

    *注:别人那复制来的 Spring提供了一个JmsTransactionManager用于对JMS ConnectionFactory做事务管理.这将允许JMS应用利用Spring的事务管理特性.Jm ...

  7. Spring Security 解析(五) —— Spring Security Oauth2 开发

    Spring Security 解析(五) -- Spring Security Oauth2 开发   在学习Spring Cloud 时,遇到了授权服务oauth 相关内容时,总是一知半解,因此决 ...

  8. Spring Cloud 学习 之 Spring Cloud Eureka(源码分析)

    Spring Cloud 学习 之 Spring Cloud Eureka(源码分析) Spring Boot版本:2.1.4.RELEASE Spring Cloud版本:Greenwich.SR1 ...

  9. Spring Cloud 学习 之 Spring Cloud Eureka(搭建)

    Spring Boot版本:2.1.4.RELEASE Spring Cloud版本:Greenwich.SR1 文章目录 搭建服务注册中心: 注册服务提供者: 高可用注册中心: 搭建服务注册中心: ...

随机推荐

  1. WPF 选项卡

    1.引用 xmlns:xcad="http://schemas.xceed.com/wpf/xaml/avalondock" 2.xaml代码 <xcad:DockingMa ...

  2. 20165312 实验一 Java开发环境的熟悉

    20165312 实验一 Java开发环境的熟悉 一.实验内容及步骤 (一)使用JDK编译.运行简单的Java程序 Ctrl+Shift+T打开终端 输入cd cxgg20165312/test进入目 ...

  3. shell脚本四-三剑客

    Shell编程——三剑客 简介 Grep:默认不支持扩展表达式,加-E或者egrep Awk:支持所有zhengze Sed默认不支持扩展表达式,加-r 2.sed语法格式 Sed 选项 命令 文件( ...

  4. 【Linux】【Jenkins】配置过程中,立即构建时,maven找不到的问题解决方案

    在Linux环境下配置Jenkins执行时,发现不能执行Maven,这个比较搞了. A Maven installation needs to be available for this projec ...

  5. jquery中live is not a function的问题

    jquery中的live()方法在jquery1.9及以上的版本中已被废弃了,如果使用,会抛出TypeError: $(...).live is not a function错误. 解决方法: 之前的 ...

  6. ZIP压缩输入/输出流

    ZIP是压缩文件的格式,使用ZIP可以节省空间 java将压缩/解压缩文件的方法都封装在java.util.zip包下,java实现了I/O数据流和网络数据流的单一接口,所以实现起来比较容易. 主要的 ...

  7. django 验证码实现

    django验证码的使用: 验证码的作用:用于人机识别. 验证码 ###验证码: def code_str(request): from PIL import Image from PIL impor ...

  8. 【Django】RROR 2003 (HY000): Can't connect to MySQL server on 'localhost' (10061)

    刚刚启动项目的时候,突然报了这个错误.之前一直正常 后来百度一下,让我在window的host文件下,把被注释的127.0.0.1   localhost这个的注释取消 然鹅并木有用 直接用cmd连接 ...

  9. Python设计模式 - UML - 类图(Class Diagram)

    简介 类图是面向对象分析和设计的核心,用来描述系统各个模块中类与类之间.接口与接口之间.类与接口之间的关系,以及每个类的属性.操作等特性,一般在详细设计过程中实施. 类图本身就是现实世界的抽象,是对系 ...

  10. Flask最强攻略 - 跟DragonFire学Flask - 第一篇 你好,我叫Flask

    首先,要看你学没学过Django 如果学过Django 的同学,请从头看到尾,如果没有学过Django的同学,并且不想学习Django的同学,轻饶过第一部分 一. Python 现阶段三大主流Web框 ...