访问数据库基本是所有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. 基于CentOS搭建个人Leanote云笔记本

    Leanote 依赖 MongoDB 作为数据存储,下面开始安装MongoDB: 1. 下载启动 MongoDB 下载 MongoDB 进入 /home 目录,并下载 MongoDB: cd /hom ...

  2. 记一次sshd启动报错,Failed to start OpenSSH server daemon.

    sshd -t [root@mysql5-slave proj]# sshd -t @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ...

  3. 第二章 FFmpeg常用命令

    2.1 FFmpeg常见的命令大概分为6个部分 ffmpeg信息查询部分 公共操作参数部分 文件主要操作参数部分 视频操作参数部分 字幕操作参数部分 2.1.1 FFmpeg的封装转换 FFmpeg ...

  4. Vue面试题

    Vue 简述下MVVM MVVM全称是MODEL-VIEW-VIEWMODEL Vue是以数据为驱动,Vue自身将DOM和数据进行绑定,一旦创建绑定,DOM和数据将保持同步,当数据发生变化,DOM也会 ...

  5. Redis梳理

  6. json初接触

    <html lang="en"> <head> <meta charset="UTF-8"> <meta name=& ...

  7. python3中一句话定义函数

    import math as marea=lambda r:r**2*m.pi #定义一个计算圆的面积的函数area(8) 显示结果 201.06192982974676

  8. LVM逻辑卷疑问?

    创建完逻辑卷后,删除以/dev/vdb1和/dev/vdb2为基础的分区后,逻辑卷依然生效???

  9. C++ 日志生成 DLL

    示例: #define log_dbg(format,args...) \        printf("[DBG] [%s: %s() line:%d]: "format ,__ ...

  10. Python爬虫中文小说网点查找小说并且保存到txt(含中文乱码处理方法)

    从某些网站看小说的时候经常出现垃圾广告,一气之下写个爬虫,把小说链接抓取下来保存到txt,用requests_html全部搞定,代码简单,容易上手. 中间遇到最大的问题就是编码问题,第一抓取下来的小说 ...