概述
jdbc是java连接数据库操作的原生接口
jpa是java持久化规范,是orm框架的标准,主流orm框架都实现了这个标准
spring data jpa是对jpa规范的再次抽象,底层还是用的实现jpa的hibernate技术
hibernate是一个标准的orm框架,实现了jpa
mybatis也是一个持久化框架,但不完全是一个orm框架,不是依照的jpa规范。
什么是orm?
orm(Object Relation Mapping) 对象关系映射,是对象持久化的核心,是对jdbc的封装。
hibernate VS mybatis VS jdbc
jdbc是比较底层的数据库操作方式,hibernate和mybatis都是在jdbc的基础上进行了封装。
hibernate是将数据库中的数据表映射为持久层的java对象,实现对数据表的完整性控制。hibernate的主要思想是面向对象,标准的orm。不建议自己写sql语句,如果确实有必要推荐hql代替。hibernate是全表映射,只需提供java bean和数据库表映射关系,
mybatis是将sql语句中的输入参数parameterMap和输出结果resultMap映射为java对象,放弃了对数据表的完整性控制,获得了更大的灵活性。mybatis拥抱sql,在sql语句方面有更大的灵活性,mybatis不是面向对象,不是标准的orm,更像是sql mapping框架。mybatis是半自动的,需要提供java bean,sql语句和数据库表的映射关系。
开发难度:
Hibernate因为是封装了完整的对象关系映射,内部实现比较复杂,学习周期大。
mybatis主要是配置文件中sql语句的编写
spring data上手快,通过命名规范,注解查询可简化操作
总结
如果是进行底层编程,需要对性能要求高,应采用jdbc方式。
如果直接操作数据库表,没有过多的定制,建议使用hibernate方式。
如果要灵活使用sql语句,建议采用mybatis方式。
JPA 的底层实现是一些流行的开源 ORM 框架,因此JPA其实也就是java实体对象和关系型数据库建立起映射关系,通过面向对象编程的思想操作关系型数据库的规范
Getting started with Spring Data JPA
(当无心阅读英文,那就直接看代码,代码才是真正的天堂,如果自己动手运行一把,那就更加完美
其实习惯性阅读英文,会让你感觉更加靠近你梦想的技术世界)
最终目的 使用 Spring Data JPA 简化 JPA 开发
Spring集成JPA2.0
JPA的使用
进化过程- – – -丰富壮大
spring-jdbc:jdbc的原生方式开发和事务的使用 spring-jdbcTemplate:使用spring封装的JdbcTemplate开发和事务的使用 spring-hibernate-xml: hibernate的原生xml方式开发 spring-hibernate-xml-tx:hibernate的原生xml方式的事务的使用 spring-hibernate-annotation:hibernate的原生的注解方式开发 spring-hibernate-annotation-tx:hibernate的原生的注解方式的事务的使用 spring-jpa-hibernate:jpa的原生xml方式开发和事务的使用 spring-springjpa-hibernate:jpa的spring集成方式开发和事务的使用 spring-springjpa-hibernate-multDataSource:多数据源下jpa与spring集成开发和事务的使用 spring-data-jpa-hibernate:spring-data-jpa方式开发和事务的使用12345678910
<一> spring-jdbc:jdbc的原生方式开发和事务的使用
第一步: 先注册驱动类
Class.forName("com.mysql.jdbc.Driver");12
第二步: 使用DriverManager来获取连接Connection
Connection conn=DriverManager.getConnection(url, user, password);12
第三步: 使用Connection来执行sql语句,以及开启、回滚、提交事务
Connection conn=jdbcDao.getConnection();
conn.setAutoCommit(false);
try {
PreparedStatement ps=conn.prepareStatement("insert into user(id,name) value(?,?)");
ps.setString(1,user.getId());
ps.setInt(2,user.getName());
ps.execute();
conn.commit();
} catch (Exception e) {
e.printStackTrace();
conn.rollback();
}finally{
conn.close();
}1234567891011121314
缺点: 每次都是获取一个连接,用完之后就释放掉,应该是用完再放回去,等待下一次使用,所以应该使用连接池datasource12
<二>spring-jdbcTemplate:使用spring封装的JdbcTemplate开发和事务的使用
第一步: 首先注册dataSource,用于管理Connection,每次使用完Connection,仍旧放回连接池,等待下一次使用
<bean id="dataSource"
class="com.##.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass">
<value>${jdbc.driverClass}</value>
</property>
<property name="jdbcUrl">
<value>${jdbc.url}</value>
</property>
<property name="username">
<value>${jdbc.user}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
<!--连接池中最小连接数。-->
<property name="minPoolSize">
<value>${jdbc.minPoolSize}</value>
</property>
<!--连接池中最大连接数 -->
<property name="maxPoolSize">
<value>${jdbc.maxPoolSize}</value>
</property>
<!--初始化时获取的连接数 -->
<property name="initialPoolSize">
<value>${jdbc.initialPoolSize}</value>
</property> </bean>12345678910111213141516171819202122232425262728
第二步 然后注册jdbcTemplate,使用上述dataSource
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean>123
第三步 事务,要注册对应的事务管理器,这里使用的是dataSource,所以要使用DataSourceTransactionManager
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean>123
第四步 然后开启注解式的事务配置,即开启@Transactional的功能
<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/>1
第五步 Spring的@Transactional,则是使用SpringAOP来对我们的SysUserDao进行,采用的是proxy-target-class=“true” 表示我们要使用cglib来进行代理我们的Dao
<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/>1
首先我们知道jdbcTemplate原理是就是对jdbc的封装 jdbc中执行sql的Connection和执行事务功能的的Connection必须是同一个Connection 后面要实现业务代码和事务代码的分离,所以必须要确保分离之后的两者使用的是同一个Connection,否则事务是不起作用的。 1234
hibernate的原生xml方式
第一步 hibernate.cfg.xml : 用于配置数据库连接和方言等等
<hibernate-configuration> <session-factory name="hibernateSessionFactory"> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/</property> <property name="hibernate.connection.username">bbl</property> <property name="hibernate.connection.password">bbl</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <property name="hibernate.show_sql">true</property> <property name="hibernate.default_schema">test</property> <mapping resource="hibernate/mapping/SysUser.hbm.xml"/> </session-factory></hibernate-configuration>123456789101112
第二步 SysUser.hbm.xml:用于配置实体SysUser和数据库SysUser表之间的关系
<hibernate-mapping> <class name="com.demo.entity.SysUser" table="sysUser"> <id name="id" column="id" type="long"> <generator class="identity"/> </id> <property name="name" column="name" type="string"/> </class> </hibernate-mapping>12345678
主要的对象 SessionFactory、Session、Transaction 这些都是hibernate的原生的对象 SessionFactory 刚才加载hibernate.cfg.xml配置文件就产生了这样的一个session工厂,它负责创建session Session 简单理解起来就是:Session和jdbc中一个Connection差不多,Session对Connection进行了封装 Transaction 是hibernate自己的事务对象接口定义,通过session可以开启一个事务,使用如下:123456789
Transaction tx=null;try {
tx=session.beginTransaction();
session.save(user);
tx.commit();
} catch (Exception e) { if(tx!=null){
tx.rollback();
}
}finally{
session.close();
}
@Repositorypublic class HibernateDao { private SessionFactory sessionFactory; public HibernateDao(){
Configuration config=new Configuration();
config.configure("hibernate/hibernate.cfg.xml");
sessionFactory=config.buildSessionFactory();
} public Session openSession(){ return sessionFactory.openSession();
}
}public class SysUserDao {
@Autowired private HibernateDao hibernateDao; public void save(SysUser user){
Session session=hibernateDao.openSession();
Transaction tx=null; try {
tx=session.beginTransaction();
session.save(user);
tx.commit();
} catch (Exception e) { if(tx!=null){
tx.rollback();
}
}finally{
session.close();
}
}
}123456789101112131415161718192021222324252627282930313233343536373839404142434445
总结 : 先根据hibernate.cfg.xml配置文件来创建SessionFactory,然后我们每次就可以通过SessionFactory来获取一个Session,然后通过Session来开启一个事务Transaction,来回滚或者提交1
hibernate的原生xml方式与spring集成以及事务的使用
第一步:注册dataSource
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass">
<value>${jdbc.driverClass}</value>
</property>
<property name="jdbcUrl">
<value>${jdbc.url}</value>
</property>
<property name="user">
<value>${jdbc.user}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
<!--连接池中最小连接数。-->
<property name="minPoolSize">
<value>${jdbc.minPoolSize}</value>
</property>
<!--连接池中最大连接数。 -->
<property name="maxPoolSize">
<value>${jdbc.maxPoolSize}</value>
</property>
<!--初始化时获取的连接数 -->
<property name="initialPoolSize">
<value>${jdbc.initialPoolSize}</value>
</property> </bean>12345678910111213141516171819202122232425262728
第二步:使用spring的LocalSessionFactoryBean来创建SessionFactory
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="mappingResources"> <list> <value>hibernate/mapping/SysUser.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <value> hibernate.dialect=org.hibernate.dialect.MySQLDialect hibernate.show_sql=true </value> </property> </bean>1234567891011121314
第三步:注册hibernate的事务管理器 HibernateTransactionManager
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean>123
第四步:启用spring的@Transactional的注解支持
<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/>1
使用
@Repository
public class UserDao {
@Autowired
private SessionFactory sessionFactory;
@Transactional
public void save(SysUser user){
//Session session=sessionFactory.openSession();
Session session=sessionFactory.getCurrentSession();
session.save(user);
throw new RuntimeException();
}1234567891011
}
总结 在执行save方法之前,使用了HibernateTransactionManager开启了相应的事务 先使用sessionFactory的openSession()来创建一个session 使用session从dataSource中获取了一个connection 使用session的getTransaction方法开启了一个Hibernate的一个Transaction事务 session.save(user); 使用session来持久化user12345678
hibernate的注解方式开发与Spring集成和事务的使用
xml方式:<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="mappingResources"> <list> <value>hibernate/mapping/SysUser .hbm.xml</value> </list> </property> //其他略</bean>注解方式:<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="packagesToScan"> <list> <value>com.demo.entity</value> </list> </property> //其他略</bean>123456789101112131415161718
jpa原生开发和事务的使用
jpa仅仅是一层接口规范
第一步:就是jpa的核心配置文件 persistence.xml
默认情况下该配置文件存放的位置是classpath路径下 META-INF/persistence.xml。配置文件的内容如下:
<persistence-unit name="test" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <properties> <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" /> <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/test" /> <property name="hibernate.connection.username" value="root" /> <property name="hibernate.connection.password" value="ligang" /> <property name="hibernate.show_sql" value="true" /> <property name="hibernate.hbm2ddl.auto" value="update" /> </properties> </persistence-unit>1234567891011
第二步: 根据核心配置文件创建EntityManagerFactory
EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("test");1
第三步:根据EntityManagerFactory创建出EntityManager
EntityManager entityManager=entityManagerFactory.createEntityManager();1
第四步 : 根据EntityManager对实体entity进行增删改查
entityManager.save(user);1
说明
PersistenceProvider接口:
根据持久化单元名称和配置参数创建出EntityManagerFactory,接口定义如下:public interface PersistenceProvider {
public EntityManagerFactory createEntityManagerFactory(String emName, Map map); public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map);
}
jpa仅仅是一层接口规范,不同的底层的实现者提供各自的provider。如hibernate提供的provider实现是org.hibernate.jpa.HibernatePersistenceProvider
EntityManagerFactory接口:
就是EntityManager的工厂。其实可以类似于Hibernate中的SessionFactory。对于Hibernate来说,其实它就是对SessionFactory的封装,Hibernate实现的EntityManagerFactory是EntityManagerFactoryImpl,源码如下:public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
private final transient SessionFactoryImpl sessionFactory; //略}
EntityManager接口:
能够对实体entity进行增删改查,其实可以类似于Hibernate中的Session。对于Hibernate来说,其实它就是对Session的封装。Hibernate实现的EntityManager是EntityManagerImpl,源码如下:public class EntityManagerImpl extends AbstractEntityManagerImpl implements SessionOwner {
protected Session session; //略}
EntityTransaction接口:
jpa定义的事务接口,其实可以类似于Hibernate原生的的Transaction接口。对于Hibernate来说,其实它就是对Transaction的封装。Hibernate实现的EntityTransaction是TransactionImpl,源码如下:public class TransactionImpl implements EntityTransaction {
private Transaction tx; //略}1234567891011121314151617181920212223242526272829303132
使用
@Repositorypublic class JpaTestDao {
private EntityManagerFactory entityManagerFactory; public JpaTestDao (){
entityManagerFactory=Persistence.createEntityManagerFactory("test");
} public EntityManager getEntityManager(){ return entityManagerFactory.createEntityManager();
}
}@Repositorypublic class SysUserDao {
@Autowired
private JpaTestDao TestDao; public void save(SysUseruser){
EntityManager entityManager=TestDao.getEntityManager();
EntityTransaction tx=null; try {
tx=entityManager.getTransaction();
tx.begin();
entityManager.persist(user);
tx.commit();
} catch (Exception e) { if(tx!=null){
tx.rollback();
}
}finally{
entityManager.close();
}
}
}1234567891011121314151617181920212223242526272829303132
jpa与spring的集成
第一步:配置数据库连接池dataSource
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass">
<value>${jdbc.driverClass}</value>
</property>
<property name="jdbcUrl">
<value>${jdbc.url}</value>
</property>
<property name="user">
<value>${jdbc.user}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
<!--连接池中最小连接数。-->
<property name="minPoolSize">
<value>${jdbc.minPoolSize}</value>
</property>
<!--连接池中最大连接数。-->
<property name="maxPoolSize">
<value>${jdbc.maxPoolSize}</value>
</property>
<!--初始化时获取的连接数-->
<property name="initialPoolSize">
<value>${jdbc.initialPoolSize}</value>
</property> </bean>12345678910111213141516171819202122232425262728
第二步:配置entityManagerFactory
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="database" value="MYSQL"/> <property name="showSql" value="true"/> <property name="generateDdl" value="true"/> <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/> <property name="packagesToScan" value="com.demo.entity"/> </bean>1234567891011
第三步:配置事务管理器JpaTransactionManager
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"></property> </bean>123
第四步:启动@Transactional注解的处理器
<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/>1
使用
@Repositorypublic class SysUserDao {
@PersistenceContext
private EntityManager entityManager; @Transactional
public void save(SysUser user){
entityManager.persist(user);
}
}1234567891011
总结
@PersistenceContext注解来获取entityManagerFactory创建的EntityManager对象,然后使用EntityManager进行增删改查
如何创建EntityManagerFactory :
可以看到spring是使用了一个工厂bean LocalContainerEntityManagerFactoryBean来创建entityManagerFactory。虽然配置的是一个工厂bean,但是容器在根据id来获取bean的时候,返回的是该工厂bean所创建的实体,即LocalContainerEntityManagerFactoryBean所创建的EntityManagerFactory。
方式1:当LocalEntityManagerFactoryBean本身指定了PersistenceProvider,就使用该PersistenceProvider来创建EntityManagerFactory,详见上文的PersistenceProvider接口定义 public class LocalEntityManagerFactoryBean extends AbstractEntityManagerFactoryBean {
@Override protected EntityManagerFactory createNativeEntityManagerFactory()
throws PersistenceException {
PersistenceProvider provider = getPersistenceProvider(); if (provider != null) { // Create EntityManagerFactory directly through PersistenceProvider.
EntityManagerFactory emf = provider.createEntityManagerFactory
(getPersistenceUnitName(), getJpaPropertyMap()); return emf;
} else { // Let JPA perform its standard PersistenceProvider autodetection.
return Persistence.createEntityManagerFactory(
getPersistenceUnitName(), getJpaPropertyMap());
}
} //略了部分内容}
方式2:使用上文jpa原生方式的:
EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("test");
它其实也是先获取所有的PersistenceProvider,然后遍历PersistenceProvider来创建EntityManagerFactory,源码如下:public static EntityManagerFactory createEntityManagerFactory(String
persistenceUnitName, Map properties) {
EntityManagerFactory emf = null; List<PersistenceProvider> providers = getProviders(); for ( PersistenceProvider provider : providers ) {
emf = provider.createEntityManagerFactory( persistenceUnitName, properties ); if ( emf != null ) { break;
}
} if ( emf == null ) { throw new PersistenceException( "No Persistence provider
for EntityManager named " + persistenceUnitName );
} return emf;
}123456789101112131415161718192021222324252627282930313233343536373839404142434445
多数据源下jpa与spring集成开发和事务的使用
第一步 配置两个数据库连接池dataSource
<bean id="dataSource1"
class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass">
<value>${jdbc1.driverClass}</value>
</property>
<property name="jdbcUrl">
<value>${jdbc1.url}</value>
</property>
//略,见项目中的配置</bean>
<!-- 配置数据源 -->
<bean id="dataSource2"
class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass">
<value>${jdbc2.driverClass}</value>
</property>
<property name="jdbcUrl">
<value>${jdbc2.url}</value>
</property>
//略,见项目中的配置
</bean>123456789101112131415161718192021222324
第二步 配置2个entityManagerFactory
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="database" value="MYSQL"/> <property name="showSql" value="true"/> <property name="generateDdl" value="true"/> <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/> </bean> <bean id="entityManagerFactory1" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource1"/> <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/> <property name="packagesToScan" value="com.demo.entity"/> </bean> <bean id="entityManagerFactory2" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource2"/> <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/> <property name="packagesToScan" value="com.demo.entity"/> <property name="persistenceUnitName" value="test2"/> </bean> 这两个entityManagerFactory使用不同的dataSource,各自有一个persistenceUnitName名字(持久化单元的名字),分别叫"test1"和"test2”。在上文中,并没有配置persistenceUnitName,采用默认值"default”1234567891011121314151617181920
第三步 配置2个事务管理器
<bean id="transactionManager1" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory1"></property> </bean> <bean id="transactionManager2" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory2"></property> </bean>1234567
第四步 开启@Transactional的处理器
<tx:annotation-driven proxy-target-class="true"/>1
使用
@Repositorypublic class SysUserDao {
@PersistenceContext(unitName="test1") private EntityManager entityManager; @PersistenceContext(unitName="test2") private EntityManager entityManagerTest2; @Transactional("transactionManager1") public void save(SysUser user){
entityManager.persist(user);
} @Transactional("transactionManager2") public void save2(SysUseruser){
entityManagerTest2.persist(user);
}
}1234567891011121314151617
spring-data-jpa的开发和事务的使用
第一步 配置dataSource
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass">
<value>${jdbc.driverClass}</value>
</property>
<property name="jdbcUrl">
<value>${jdbc.url}</value>
</property>
//略
</bean>1234567891011
第二步 配置entityManagerFactory
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="database" value="oracle/mysql"/> <property name="showSql" value="true"/> <property name="generateDdl" value="true"/> <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/> <property name="packagesToScan" value="com.demo.entity"/> </bean>123456789101112
第三步 配置transactionManager
第四步 开启@Transactional的处理器
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"></property> </bean> 第三步 <tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/> 第四步123456
第五步 配置要扫描的dao的路径
<jpa:repositories base-package="com.sys.dao"/>1
使用
public interface SysUserDao extends CrudRepository<SysUser,Long>{
}
@Autowiredprivate UserDao userDao;


