这是Project Student的一部分。 其他职位包括带有Jersey的Webservice Client,带有Jersey的 Webservice Server和业务层 。

RESTful webapp onion的最后一层是持久层。

持久层有两种哲学。 一个阵营将数据库视为一个简单的存储,并希望保持这一层非常薄。 另一阵营知道,在数据库中执行任务通常比访问数据库中的数据,用Java完成必要的工作以及第二次访问结果要快得多。 该阵营通常需要一个相当厚的持久层。

第二个阵营也有一群希望广泛使用存储过程的流放者。 这使数据库功能更加强大,但在持久层中却付出了一些额外的复杂性。 它的主要缺点是存储过程是特定于数据库的。

第二批流亡者仅使用存储过程来提高安全性。 我已经在前面进行了讨论,例如,您应该使用用户名和密码来调用存储过程并获得“接受”或“拒绝”响应,而不是检索哈希密码并在应用程序中进行比较。 第一种方法允许您使用数据库的GRANT和REVOKE特权将哈希密码存储在不可访问的表中,即使攻击者可以以应用程序用户身份执行任意SQL注入。

(旁注:您通常可以用Java编写存储过程!Oracle支持它,PostgreSQL支持它(通过PL / Java扩展),H2支持它(通过类路径)。我不知道MySQL是否支持它。这种方法有确定的成本,但这可能是解决许多问题的最佳解决方案。)

无论如何,该项目目前仅支持CRUD操作,它们是使用薄型持久层的经典示例。 但是添加“ thick”方法很容易–只需使用它们创建一个CourseRepositoryImpl类。 (此类不应实现CourseRepository接口!)

设计决策

Spring Data –我们正在使用Spring Data,因为它会自动生成持久层类。

局限性

分页 –没有尝试支持分页。 由于Spring Data已经支持它,所以这不是一个大问题-我们只需要编写胶水即可。

组态

基本配置仅需要@EnableJpaRepositories批注。

使用纯内存嵌入式数据库的集成测试需要更多的工作。 即使使用H2网址(告诉它使数据库服务器不工作),也不能直接使用Spring嵌入式数据库。 数据库已正确初始化,但在测试实际运行之前已关闭。 由于缺少数据库架构,结果是失败。

使用由文件支持的内存数据库是微不足道的,但可能导致并发运行问题,意外拉入旧的测试数据等。显而易见的解决方案是使用随机临时支持文件,但这种方法引入了自己的问题。

下面的方法是将嵌入式数据库缓存在配置类中,并仅在应用程序关闭时销毁它。 这引入了一些非显而易见的行为,迫使我们也必须显式创建一些其他bean。

(IIRC,如果您在配置类中创建嵌入式数据库,并在配置文件中创建事务Bean,则spring在配置文件中创建幻像数据源,并且初始化失败。当我开始在同一文件中创建事务Bean时,此问题消失了放置为数据源。)

@Configuration
@EnableJpaRepositories(basePackages = { "com.invariantproperties.sandbox.student.repository" })
@EnableTransactionManagement
@PropertySource("classpath:test-application.properties")
@ImportResource("classpath:applicationContext-dao.xml")
public class TestPersistenceJpaConfig implements DisposableBean {private static final Logger log = LoggerFactory.getLogger(TestPersistenceJpaConfig.class);private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";private static final String PROPERTY_NAME_HIBERNATE_FORMAT_SQL = "hibernate.format_sql";private static final String PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY = "hibernate.ejb.naming_strategy";private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";private static final String PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO = "hibernate.hbm2ddl.auto";private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";// private static final String PROPERTY_NAME_PERSISTENCE_UNIT_NAME =// "persistence.unit.name";@Resourceprivate Environment environment;private EmbeddedDatabase db = null;@Beanpublic DataSource dataSource() {final EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();db = builder.setType(EmbeddedDatabaseType.H2).build(); // .script("foo.sql")return db;}@Beanpublic LocalContainerEntityManagerFactoryBean entityManagerFactory() throws ClassNotFoundException {LocalContainerEntityManagerFactoryBean bean = new LocalContainerEntityManagerFactoryBean();bean.setDataSource(dataSource());bean.setPackagesToScan(environment.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));bean.setPersistenceProviderClass(HibernatePersistence.class);// bean.setPersistenceUnitName(environment// .getRequiredProperty(PROPERTY_NAME_PERSISTENCE_UNIT_NAME));HibernateJpaVendorAdapter va = new HibernateJpaVendorAdapter();bean.setJpaVendorAdapter(va);Properties jpaProperties = new Properties();jpaProperties.put(PROPERTY_NAME_HIBERNATE_DIALECT,
environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));jpaProperties.put(PROPERTY_NAME_HIBERNATE_FORMAT_SQL,environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_FORMAT_SQL));jpaProperties.put(PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY,environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY));jpaProperties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL,environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));jpaProperties.put(PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO,environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO));bean.setJpaProperties(jpaProperties);return bean;}@Beanpublic PlatformTransactionManager transactionManager() {JpaTransactionManager tm = new JpaTransactionManager();try {tm.setEntityManagerFactory(this.entityManagerFactory().getObject());} catch (ClassNotFoundException e) {// TODO: log.}return tm;}@Beanpublic PersistenceExceptionTranslationPostProcessor exceptionTranslation() {return new PersistenceExceptionTranslationPostProcessor();}@Overridepublic void destroy() {if (db != null) {db.shutdown();}}
}

applicationContext.xml文件为空。 该属性文件是:

# hibernate configuration
hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.ejb.naming_strategy=org.hibernate.cfg.ImprovedNamingStrategy
hibernate.show_sql=false
hibernate.format_sql=true
hibernate.hbm2ddl.auto=create# jpa configuration
entitymanager.packages.to.scan=com.invariantproperties.sandbox.student.domain
persistence.unit.dataSource=java:comp/env/jdbc/ssDS
persistence.unit.name=ssPU

单元测试

由于所有代码都是自动生成的,因此没有单元测试。 这将随着添加自定义方法而改变。

整合测试

现在,我们可以编写业务层的集成测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { BusinessApplicationContext.class, TestBusinessApplicationContext.class,TestPersistenceJpaConfig.class })
@Transactional
@TransactionConfiguration(defaultRollback = true)
public class CourseServiceIntegrationTest {@Resourceprivate CourseService dao;@Testpublic void testCourseLifecycle() throws Exception {final String name = "Calculus 101";final Course expected = new Course();expected.setName(name);assertNull(expected.getId());// create courseCourse actual = dao.createCourse(name);expected.setId(actual.getId());expected.setUuid(actual.getUuid());expected.setCreationDate(actual.getCreationDate());assertThat(expected, equalTo(actual));assertNotNull(actual.getUuid());assertNotNull(actual.getCreationDate());// get course by idactual = dao.findCourseById(expected.getId());assertThat(expected, equalTo(actual));// get course by uuidactual = dao.findCourseByUuid(expected.getUuid());assertThat(expected, equalTo(actual));// update courseexpected.setName("Calculus 102");actual = dao.updateCourse(actual, expected.getName());assertThat(expected, equalTo(actual));// delete Coursedao.deleteCourse(expected.getUuid());try {dao.findCourseByUuid(expected.getUuid());fail("exception expected");} catch (ObjectNotFoundException e) {// expected}}/*** @test findCourseById() with unknown course.*/@Test(expected = ObjectNotFoundException.class)public void testfindCourseByIdWhenCourseIsNotKnown() {final Integer id = 1;dao.findCourseById(id);}/*** @test findCourseByUuid() with unknown Course.*/@Test(expected = ObjectNotFoundException.class)public void testfindCourseByUuidWhenCourseIsNotKnown() {final String uuid = "missing";dao.findCourseByUuid(uuid);}/*** Test updateCourse() with unknown course.* * @throws ObjectNotFoundException*/@Test(expected = ObjectNotFoundException.class)public void testUpdateCourseWhenCourseIsNotFound() {final Course course = new Course();course.setUuid("missing");dao.updateCourse(course, "Calculus 102");}/*** Test deleteCourse() with unknown course.* * @throws ObjectNotFoundException*/@Test(expected = ObjectNotFoundException.class)public void testDeleteCourseWhenCourseIsNotFound() {dao.deleteCourse("missing");}
}

源代码

  • 可从http://code.google.com/p/invariant-properties-blog/source/browse/student/student-business和http://code.google.com/p/invariant-properties-获得源代码。 blog / source / browse / student / student-persistence 。
参考: 项目学生: Invariant Properties博客上来自我们JCG合作伙伴 Bear Giles的Spring数据的持久性 。

翻译自: https://www.javacodegeeks.com/2014/01/project-student-persistence-with-spring-data.html

项目学生:Spring数据的持久性相关推荐

  1. spring 事务持久性_项目学生:Spring数据的持久性

    spring 事务持久性 这是Project Student的一部分. 其他职位包括带有Jersey的Webservice Client,带有Jersey的 Webservice Server和业务层 ...

  2. web 项目集成福昕_项目学生:Web服务集成

    web 项目集成福昕 这是Project Student的一部分. 其他帖子包括带有Jersey的 Web服务 客户端,带有Jersey的 Web服务服务器 , 业务层 , 具有Spring数据的持久 ...

  3. 项目学生:Web服务集成

    这是Project Student的一部分. 其他职位包括带有Jersey的 Web服务 客户端,带有Jersey的 Web服务服务器 , 业务层 , 具有Spring数据的持久性和分片集成测试数据 ...

  4. spring 启动加载数据_12个很棒的Spring数据教程来启动您的数据项目

    spring 启动加载数据 Spring Data的任务是为数据访问提供一个熟悉且一致的,基于Spring的编程模型,同时仍保留基础数据存储的特​​殊特征. 它使使用数据访问技术,关系和非关系数据库, ...

  5. 12个很棒的Spring数据教程来启动您的数据项目

    Spring Data的任务是为数据访问提供一个熟悉且一致的,基于Spring的编程模型,同时仍保留基础数据存储的特​​殊特征. 它使使用数据访问技术,关系和非关系数据库,map-reduce框架以及 ...

  6. 复习Java第一个项目学生信息管理系统 04(权限管理和动态挂菜单功能) python简单爬数据实例Java面试题三次握手和四次挥手生活【记录一个咸鱼大学生三个月的奋进生活】016

    记录一个咸鱼大学生三个月的奋进生活016 复习Java(学生信息管理系统04权限管理和动态挂菜单功能) 改写MainFrame的构造方法 新增LoginFrame的验证登录是否成功的代码 新增Logi ...

  7. 集成测试还原数据库_项目学生:分片集成测试数据

    集成测试还原数据库 这是Project Student的一部分. 其他职位包括带有Jersey的Webservice Client,带有Jersey的 Webservice Server , 业务层和 ...

  8. 项目学生:分片集成测试数据

    这是Project Student的一部分. 其他职位包括带有Jersey的 Web服务 客户端,带有Jersey的 Web服务服务器 , 业务层和带有Spring Data的持久性 . 到目前为止, ...

  9. aop 代码_项目学生:使用AOP简化代码

    aop 代码 这是Project Student的一部分. 许多人坚信方法应适合您的编辑器窗口(例如20行),而有些人认为方法应小于此范围. 这个想法是一种方法应该做一件事,而只能做一件事. 如果它做 ...

最新文章

  1. java中static作用详解
  2. 冲刺 (sprint) 评审会议
  3. jfinal上传文件
  4. 开放下载!复旦大学邱锡鹏教授发布教科书《神经网络与深度学习》
  5. 我的技术回顾2019不止技术的一年
  6. java学习(71):GUL边界布局管理器
  7. 双路服务器单路运行,单路还是双路?看需求选择_机箱电源评测-中关村在线
  8. 双向链表(带头结点)
  9. centos 6.7 mysql 5.6_CentOS 6.7 安装 MySQL 5.6 思路整理
  10. 叫板抖音,运营商入局短视频
  11. Codeforces - 474D - Flowers - 构造 - 简单dp
  12. mysql 当前时间的一周后_mysql查询当前时间,一天内,一周,一个月内的sql语句...
  13. 大一c语言编程上机题库,C语言上机题库Word版
  14. 【24】NumPy IO
  15. Python自动化测试进阶系列——自动发邮件功能
  16. 开始起飞-golang编码技巧分享--Dave Cheney博客读后整理
  17. 如何来隐藏自己本地的ip地址进行上网?
  18. realmeq参数配置详情_realmeq参数配置-realmeq手机性能规格详情
  19. echarts legend图例显示数值和百分比
  20. 用Python构建区块链

热门文章

  1. Android碎片Fragment详讲(1)
  2. foxmail 不知道这样的主机_华为P50真机图!网友:早知道这样,就不加价买mate40了...
  3. 键盘录入一个正整数,把它的各个位上的数字倒着排列形成一个新的整数并输出。 例如:12345 数出54321 78760 输出6787(0省去)
  4. pivot sqlserver 条件_行转列之SQLSERVERPIVOT与用法详解
  5. 电脑任务栏跑到右边去了_电脑没有声音怎么解决 电脑没有声音解决方法【详解】...
  6. ios签名软件_苹果企业签名常常掉怎样处理【苹果签名吧】
  7. JavaScript 变量的作用域和生命周期
  8. spring mvc教程_Spring MVC教程
  9. lambda 分类聚合_使用Java 8 Lambda,流和聚合
  10. Spring @RequestParam批注