概述
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;