重构应用程序:直接数据库访问->;通过REST访问
我们有一个庞大的数据库应用程序,必须进行重构(原因有很多,最大的一个是安全性) 我们已经拥有的:重构应用程序:直接数据库访问->;通过REST访问,rest,jpa,spring-mvc,jpa-2.0,eclipselink,Rest,Jpa,Spring Mvc,Jpa 2.0,Eclipselink,我们有一个庞大的数据库应用程序,必须进行重构(原因有很多,最大的一个是安全性) 我们已经拥有的: MySQL数据库 JPA2(Eclipselink)课程,适用于100多张表格 直接访问数据库的客户端应用程序 需要什么: REST接口 通过数据库使用角色登录/注销 到目前为止我所做的: 使用Spring Security 3.1.1设置Spring MVC 3.2.1 使用自定义的UserDetailsService(仅包含用于测试atm的静态数据) 为测试创建了几个控制器(仅接收/提
- MySQL数据库
- JPA2(Eclipselink)课程,适用于100多张表格
- 直接访问数据库的客户端应用程序
- REST接口
- 通过数据库使用角色登录/注销
- 使用Spring Security 3.1.1设置Spring MVC 3.2.1
- 使用自定义的
(仅包含用于测试atm的静态数据)UserDetailsService
- 为测试创建了几个控制器(仅接收/提供数据)
- 我们的数据库中有任何@OneToMany和@ManyToMany关系
@PersistenceContext
private EntityManager em;
@RequestMapping(method=RequestMethod.GET)
public @ResponseBody List<Article> index() {
List<Article> a = em.createQuery("SELECT a FROM Article a", Article.class).getResultList();
return a;
}
(这是一本多位作者的书)。这三种选择都有不同的优缺点:
作者
模型,但是如果我通过REST请求一本书
模型,我可能现在不想要模型,但以后再要。因此,选择2更好:书
模型。然后使用authorIds
获取相应的作者。但是现在我不能简单地使用myBook.getAuthors()
书籍
s,并且只包含作者
ID,我可以执行类似的操作:idAuthorMap.put(authorId,null)
现在就这样。谢谢大家:)
可能的解决方案: 问题:仅选择我需要的数据。这意味着或多或少要忽略每个
@manytomy
,@OneToMany
,@manytomone
关系
解决方案:使用@JsonIgnore
和/或@JsonIgnoreProperties
问题:每个被忽略的关系都应该在不修改数据模型的情况下轻松获取 解决方案:示例模型:
class Book {
int bId;
Author author; // has @ManyToOne
}
class Author {
int aId;
List<Book> books; // has @OneToMany
}
教材{
国际招标;
作者;//拥有@manytone
}
类作者{
国际援助;
列出书籍;//有@OneToMany
}
现在我可以通过REST获取一本书:GET/books/4
,结果如下('因为我通过@JsonIgnore
忽略所有关系):{“bId”:4}
然后我必须创建另一条路径来接收相关作者:GET/books/4/author
。将返回:{“aId”:6}
向后:GET/authors/6/books
->[{“bId”:4},{“bId”:42}]
每个
@ManyToMany
,@OneToMany
,@manytomone
,都会有一条路线,但仅此而已。所以这个将不存在:GET/authors/6/books/42
。客户端应该使用GET/books/42
首先,您需要控制JPA层如何处理您的关系。我的意思是使用惰性加载与急切加载。这可以通过注释上的“fetch”选项轻松地进行控制,如下所示:
@OneToMany(fetch=FetchType.Lazy)
这告诉JPA的是,对于这个相关对象,只有在一些代码请求时才加载它。在幕后,正在发生的是正在生成/创建一个动态“代理”对象。当您尝试访问此代理时,它非常聪明,可以出去执行另一个SQL来收集所需的数据。在集合的情况下,当您迭代集合中的项时,它甚至可以成批地获取底层对象。但是,请注意:访问这些代理必须在同一个大会期间进行。底层ORM框架(不知道Eclipselink是如何工作的……我是Hybernate用户)将不知道如何将子请求与适当的域对象关联起来。当您使用像FlexBlazeDS这样的传输框架时,这会产生更大的影响,FlexBlazeDS尝试使用字节码而不是接口封送对象,并且在看到这些代理对象时通常会出错
您可能还需要设置级联策略,这可以通过“级联”选项完成,如
@OneToMany(cascade=CascadeType.ALL)
或者您可以给它一个列表,如:
@OneToMany(cascade={CascadeType.MERGE, CascadeType.REMOVE})
一旦控制了从数据库中提取的内容,就需要了解如何编组域对象。您是否通过JSON、XML(取决于请求的混合格式)发送此消息?您使用的是什么框架(Jackson、FlexJSON、XStream等)?问题是,即使您将fetch类型设置为Lazy,这些框架仍然会跟踪相关对象,从而否定您告诉它延迟加载的所有工作。这就是mashalling/serialization方案变得更加具体的地方:您需要弄清楚如何告诉您的框架应该封送什么和不应该封送什么。同样,这在很大程度上取决于所使用的框架。首先,您需要控制JPA层如何处理您的关系。我的意思是使用惰性加载与急切加载。这可以通过注释上的“fetch”选项轻松地进行控制,如下所示:
@OneToMany(fetch=FetchType.Lazy)
这告诉JPA的是,对于这个相关对象,只有在一些代码请求时才加载它。在幕后,正在发生的是正在生成/创建一个动态“代理”对象。当您尝试访问此代理时,它非常聪明,可以出去执行另一个SQL来收集所需的数据。就收集而言,它是均匀的