Beginning Spring学习笔记——第5章(二)Spring的JPA支持
来源:互联网 发布:佛山新能源汽车知豆 编辑:程序博客网 时间:2024/06/06 17:42
Spring的JPA支持的好处
- 更容易且更强大的持久化单元配置,不必使用META-INF/persistence.xml
- 更容易测试
- 自动EntityManager管理,且可注入DAO Bean中
- 常见的数据访问异常,异常层次结构变为Spring的
- 集成事务管理
在Spring容器中配置JPA
Spring在同一个项目中提供三种不同方法配置EntityManagerFactory。
- LocalEntityManagerFactoryBean
最基础且功能最有限的方法,从META-INF/persistence.xml中读取JPA配置,不允许使用Spring管理的DataSource实例且不支持分布式事务管理 - 通过JNDI进行EntityManagerFactory查找
此时的Spring EntityManagerFactory Bean只不过是一个从JNDI获取的持久化单元委托 - LocalContainerEntityFactoryBean,最强大和灵活的JPA配置方法,对EntityManagerFactory完全控制
使用LocalContainerEntityManagerFactoryBean配置和使用JPA
接上一节的Book和Student类创建配置类
@Configurationpublic class Ch5Configuration { @Bean public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("org.h2.Driver"); dataSource.setUrl("jdbc:h2:tcp://localhost/~/test"); dataSource.setUsername("sa"); dataSource.setPassword(""); return dataSource; } private Map<String,?> jpaProperties() { Map<String,String> jpaPropertiesMap = new HashMap<String,String>(); jpaPropertiesMap.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect"); jpaPropertiesMap.put("hibernate.hbm2ddl.auto", "update"); return jpaPropertiesMap; } @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() { LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean(); factoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class); factoryBean.setDataSource(dataSource()); factoryBean.setPackagesToScan("com.wiley.beginningspring.ch5"); factoryBean.setJpaPropertyMap(jpaProperties()); return factoryBean; }}
为使用Spring管理的DataSource和EntityManagerFactory,主函数中也要创建Spring容器
public class Main { public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext( Ch5Configuration.class); EntityManagerFactory entityManagerFactory = applicationContext .getBean(EntityManagerFactory.class); EntityManager entityManager = entityManagerFactory .createEntityManager(); EntityTransaction transaction = entityManager.getTransaction(); transaction.begin(); Student student = new Student(); student.setFirstName("Madoka"); student.setLastName("Kaname"); entityManager.persist(student); transaction.commit(); entityManager.close(); }}
完成插入操作后查看数据库:
学生成功被插入。
基于纯JPA实现DAO
可以在字段或方法级别使用@PersistenceContext和@PersistenceUnit注解,前者表示对EntityManagerFactory的依赖,后者表示对EntityManager的依赖
使用@PersistenceUnit获取EntityManagerFactory
此时需要在Dao实现类中加入EntityManagerFactory字段并在其上放置@PersistenceUnit注解将entityManagerFactory注入到DAO类中。
public class StudentDaoJpaImpl { @PersistenceUnit private EntityManagerFactory entityManagerFactory; public void save(Student student) { EntityManager entityManager = entityManagerFactory .createEntityManager(); EntityTransaction transaction = entityManager.getTransaction(); transaction.begin(); entityManager.persist(student); transaction.commit(); entityManager.close(); }}
此时还要在配置文件中加入DAO类的Bean:
@Bean public StudentDaoJpaImpl studentDao() { StudentDaoJpaImpl dao = new StudentDaoJpaImpl(); return dao; }
然后在主函数里用该DAO类插入一个Student实例:
public class Main { public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext( Ch5Configuration.class); StudentDaoJpaImpl dao = applicationContext.getBean(StudentDaoJpaImpl.class); Student student = new Student(); student.setFirstName("Sayaka"); student.setLastName("Miki"); dao.save(student); }}
运行程序发现插入成功
使用@PersistenceContext获取EntityManager
此时要用@EnableTransactionManagement注解标识配置类启用Spring容器管理事务,新配置类为:
@Configuration@EnableTransactionManagementpublic class Ch5Configuration { @Bean public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("org.h2.Driver"); dataSource.setUrl("jdbc:h2:tcp://localhost/~/test"); dataSource.setUsername("sa"); dataSource.setPassword(""); return dataSource; } private Map<String,?> jpaProperties() { Map<String,String> jpaPropertiesMap = new HashMap<String,String>(); jpaPropertiesMap.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect"); jpaPropertiesMap.put("hibernate.hbm2ddl.auto", "update"); return jpaPropertiesMap; } @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() { LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean(); factoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class); factoryBean.setDataSource(dataSource()); factoryBean.setPackagesToScan("com.wiley.beginningspring.ch5"); factoryBean.setJpaPropertyMap(jpaProperties()); return factoryBean; } @Bean public StudentDaoJpaImpl studentDao() { StudentDaoJpaImpl dao = new StudentDaoJpaImpl(); return dao; } @Bean @Autowired public PlatformTransactionManager transactionManager( EntityManagerFactory entityManagerFactory) { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(entityManagerFactory); return transactionManager; } @Bean public BookDao bookDao() { BookDaoJpaImpl bean = new BookDaoJpaImpl(); return bean; } @Bean public BookService bookService() { BookServiceImpl bean = new BookServiceImpl(); bean.setBookDao(bookDao()); return bean; }}
然后创建BookDao接口和它的实现类进行持久化操作。由于@PersistenceContext注解是与EntityManager绑定,因此被注入的是EntityManager实例。
public interface BookDao { public void save(Book book);}public class BookDaoJpaImpl implements BookDao { @PersistenceContext private EntityManager entityManager; @Override public void save(Book book) { entityManager.persist(book); }}
再创建服务层的BookService接口和其实现类处理事务管理。
public interface BookService { public void save(Book book);}@Transactionalpublic class BookServiceImpl implements BookService { private BookDao bookDao; public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; } @Override public void save(Book book) { bookDao.save(book); }}
以上二者的Bean都已经定义在了新配置文件中完成了向服务层注入dao层。
最后在主函数中执行对bookService的Bean查找,对新的Book实体进行持久化操作。
public class Main { public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Ch5Configuration.class); BookService bookService = applicationContext.getBean(BookService.class); Book book = new Book(); book.setName("The Order of Things"); bookService.save(book); }}
运行得到结果,成功插入书籍
处理和转换异常
只需要用@Repository注解标注DAO实现类,
@Repositorypublic class BookDaoJpaImpl implements BookDao { @PersistenceContext private EntityManager entityManager; @Override public void save(Book book) { entityManager.persist(book); }}
然后在配置类中加入PersistenceExceptionTranslationPostProcessor的Bean,
@Bean public static PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor() { PersistenceExceptionTranslationPostProcessor bean = new PersistenceExceptionTranslationPostProcessor(); return bean; }
就可以在服务层通过一个try-catch语句捕捉转化为DataAccessException的异常了。
@Override public void save(Book book) { try{ //Perform some business logic here bookDao.save(book); } catch (DataAccessException ex) { //handle the data access exception without depending on particular data access technology used beneath }
在Spring环境中进一步配置JPA
JpaDialect
通过该接口可以配置如下高级功能:
- 应用特定事务语义,比如自定义隔离级别或者事务超时
- 获取事务性JDBC连接,以便向基于JDBC的DAO公开
- 将PersistenceExcept转换到Spring DataAccessException的高级功能
默认实现为不提供任何上述功能的DefaultJpaDialect,使用上述功能需要指定特定方言类,比如HibernateJpaDialect。
JpaVendorAdapter
用于激活与供应商有关的高级功能,例如可以将LocalContainerEntityManagerFactoryBean中一下代码注释掉集中配置和管理:
@Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() { LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean(); factoryBean.setDataSource(dataSource()); //factoryBean.setJpaPropertyMap(jpaProperties()); //factoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class); //factoryBean.setJpaDialect(new HibernateJpaDialect()); factoryBean.setJpaVendorAdapter(jpaVendorAdapter()); return factoryBean; } @Bean public JpaVendorAdapter jpaVendorAdapter() { HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter(); jpaVendorAdapter.setGenerateDdl(true); jpaVendorAdapter.setDatabase(Database.H2); return jpaVendorAdapter; }
JPA加载时编制
在配置类上添加@EnableLoadTimeWeaving启用加载时编织
- Beginning Spring学习笔记——第5章(二)Spring的JPA支持
- Beginning Spring学习笔记——第5章(一)ORM和JPA基础
- Beginning Spring学习笔记——第2章(三)Spring的Bean管理
- Beginning Spring学习笔记——第4章(一)Spring JDBC连接的配置
- Beginning Spring学习笔记——第2章(二)依赖注入
- Beginning Spring学习笔记——第3章(二)表单处理
- Beginning Spring学习笔记——第4章(二)使用Spring执行数据访问操作
- Beginning Spring学习笔记——第6章(二)使用Spring进行声明式事务管理
- Beginning Spring学习笔记——第1章
- Beginning Spring学习笔记——第9章 SpEL
- Beginning Spring学习笔记——第10章 缓存
- Beginning Spring学习笔记——第2章(一)Spring IoC容器
- Beginning Spring学习笔记——第3章(一)Spring MVC基础
- Beginning Spring学习笔记——第6章(一)Spring事务管理基础
- Beginning Spring学习笔记——第7章 使用Spring进行测试驱动开发
- Beginning Spring学习笔记——第8章 Spring AOP
- Beginning Spring学习笔记——第11章 使用Spring开发REST风格的Web服务
- Beginning Spring学习笔记——第6章(三)使用Spring进行编程式事务管理
- 每日两算法8.29
- JavaScript中this指针指向的彻底理解
- 解决PHP接受form表单限制1000个变量的问题
- Atitit 个人 企业 政府 等组织 财政收入分类与提升途径attilax总结 1.1. 国家财政收入分类1 1.2. 企业收入分类1 1.3. 个人收入分类1 1.1.国家财政收入分类
- 将数组中两个线性表位置互换的方式
- Beginning Spring学习笔记——第5章(二)Spring的JPA支持
- 字节输入输出流之实现图片文件的复制
- 红帽6 安装oracle 12c 详细步骤
- centos 配置tomcat(jdk)
- linux下如何使用sftp命令
- 杂七杂八
- Android Service 浅析(生命周期,启动方式,前台Service)
- 匹配两个字符串中,相同且最长的子字符串
- CNN字符级中文文本分类-基于TensorFlow实现