我正在尝试手动连接Spring Data JPA对象,以便我可以生成DAO代理(也称为存储库) - 而无需使用Spring bean容器.
不可避免地,我会被问到为什么要这样做:这是因为我们的项目已经在使用Google Guice(并且在使用Gin和GWT的UI上),我们不想维护另一个IoC容器配置,或者拉入所有产生的依赖关系.我知道我们可以使用Guice SpringIntegration,但这是最后的选择.
似乎所有东西都可用于手动连接对象,但由于它没有很好地记录,我现在遇到了困难.
根据Spring Data用户指南,可以单独使用存储库工厂.不幸的是,该示例显示了RepositoryFactorySupport哪个是抽象类.经过一番搜索,我找到了JpaRepositoryFactory
JpaRepositoryFactory实际上工作得很好,除了它不会自动创建交易.必须手动管理事务,否则任何内容都不会持久保存到数据库:
entityManager.getTransaction().begin();
repositoryInstance.save(someJpaObject);
entityManager.getTransaction().commit();
Run Code Online (Sandbox Code Playgroud)
问题原来是@Transactional注释没有自动使用,需要一个帮助TransactionInterceptor
值得庆幸的是,JpaRepositoryFactory在返回之前,可以进行回调以向生成的Repository代理添加更多AOP建议:
final JpaTransactionManager xactManager = new JpaTransactionManager(emf);
final JpaRepositoryFactory factory = new JpaRepositoryFactory(emf.createEntityManager());
factory.addRepositoryProxyPostProcessor(new RepositoryProxyPostProcessor() {
@Override
public void postProcess(ProxyFactory factory) {
factory.addAdvice(new TransactionInterceptor(xactManager, new AnnotationTransactionAttributeSource()));
}
});
Run Code Online (Sandbox Code Playgroud)
这是事情进展不顺利的地方.单步执行代码中的调试器,TransactionInterceptor确实创建了一个事务 - 但错误EntityManager.Spring EntityManager通过查看当前正在执行的线程来管理活动.这样TransactionInterceptor做并看到EntityManager线程没有活动绑定,并决定创建一个新线程.
但是,这个new EntityManager与创建并传递给JpaRepositoryFactory构造函数的实例不同,后者需要一个EntityManager.问题是,我如何制作TransactionInterceptor …
我有一个spring-mvc项目,它使用spring-data-jpa进行数据访问.我有一个域对象Travel,我想让最终用户对它应用一些过滤器.
为此,我实现了以下控制器:
@Autowired
private TravelRepository travelRep;
@RequestMapping("/search")
public ModelAndView search(
@RequestParam(required= false, defaultValue="") String lastName,
Pageable pageable) {
ModelAndView mav = new ModelAndView("travels/list");
Page<Travel> travels = travelRep.findByLastNameLike("%"+lastName+"%", pageable);
PageWrapper<Travel> page = new PageWrapper<Travel>(travels, "/search");
mav.addObject("page", page);
mav.addObject("lastName", lastName);
return mav;
}
Run Code Online (Sandbox Code Playgroud)
这很好用:用户有一个带有lastName输入框的表单,可以用来过滤旅行.
除了lastName之外,我的Travel域对象还有很多我想要过滤的属性.我认为如果这些属性都是字符串,那么我可以将它们添加为@RequestParams并添加一个spring-data-jpa方法来进行查询.例如,我添加了一个方法findByLastNameLikeAndFirstNameLikeAndShipNameLike.
但是,当我需要过滤外键时,我不知道该怎么做.所以我Travel有一个period属性是Period域对象的外键,我需要将它作为下拉列表供用户选择Period.
我想要做的是当句点为空时我想要检索由lastName过滤的所有旅行,当句点不为空时我想要检索由lastName过滤的这段时间的所有旅行.
我知道如果我在我的存储库中实现两个方法并使用一个if到我的控制器,这可以做到:
public ModelAndView search(
@RequestParam(required= false, defaultValue="") String lastName,
@RequestParam(required= false, defaultValue=null) Period period,
Pageable …Run Code Online (Sandbox Code Playgroud) 我正在查看关于方法命名的页面上的示例(http://docs.spring.io/spring-data/jpa/docs/current/reference/html/jpa.repositories.html),是否可以创建一个复杂的链方法名称,如
findByProgrammeAndDirectorAndProgDateBetweenOrderByProgDateStartTimeAsc
Run Code Online (Sandbox Code Playgroud)
在他们给出的示例中,他们只在一个值上执行OrderBy.在上面的示例中ProgDate,StartTime将是两个单独的值.
我想根据用户的特定请求从我的后端调用另一个web-api.例如我想调用google FCM发送消息api,以便在事件上向特定用户发送消息.
是改造有什么方法来实现这一目标?或者如果不是我怎么能这样做?
是否可以在不使用方法参数的情况下通过Spring Data JPA中的布尔属性进行查询?
基本上我希望这可以在不使用自定义@Query注释的情况下工作:
@Query("SELECT c FROM Entity c WHERE c.enabled = true")
public Iterable<Entity> findAllEnabled();
Run Code Online (Sandbox Code Playgroud) 我有一个spring 4应用程序,我试图从我的数据库中删除一个实体的实例.我有以下实体:
@Entity
public class Token implements Serializable {
@Id
@SequenceGenerator(name = "seqToken", sequenceName = "SEQ_TOKEN", initialValue = 500, allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seqToken")
@Column(name = "TOKEN_ID", nullable = false, precision = 19, scale = 0)
private Long id;
@NotNull
@Column(name = "VALUE", unique = true)
private String value;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "USER_ACCOUNT_ID", nullable = false)
private UserAccount userAccount;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "EXPIRES", length = 11)
private Date expires;
...
// getters and setters …Run Code Online (Sandbox Code Playgroud) 我正在尝试将自定义方法添加到我的Spring Data存储库PersonRepository,如1.3 Spring Data存储库的自定义实现中所述,并通过REST公开这些方法.初始代码来自使用REST示例访问JPA数据,以下是添加/修改类的代码:
interface PersonRepositoryCustom {
List<Person> findByFistName(String name);
}
class PersonRepositoryImpl implements PersonRepositoryCustom, InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
// initialization here
}
@Override
public List<Person> findByFistName(String name) {
// find the list of persons with the given firstname
}
}
@RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends PagingAndSortingRepository<Person, Long> {
List<Person> findByLastName(@Param("name") String name);
}
Run Code Online (Sandbox Code Playgroud)
当我运行应用程序并访问时http://localhost:8080/portfolio/search/,我得到以下响应正文:
{
"_links" : {
"findByLastName" …Run Code Online (Sandbox Code Playgroud) 我有三个JPA实体类A,B并C具有以下层次结构:
A
|
+---+---+
| |
C B
Run Code Online (Sandbox Code Playgroud)
那是:
@Entity
@Inheritance
public abstract class A { /* ... */ }
@Entity
public class B extends A { /* ... */ }
@Entity
public class C extends A { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
使用Spring Data JPA,为这些实体编写存储库类的最佳方法是什么?
我知道我可以写这些:
public interface ARespository extends CrudRepository<A, Long> { }
public interface BRespository extends CrudRepository<B, Long> { }
public interface CRespository extends CrudRepository<C, Long> …Run Code Online (Sandbox Code Playgroud) 目前,我正在使用@SpringBootApplication具有以下属性的默认注释application.properties:
spring.datasource.url=jdbc:mysql://localhost/dbname
spring.datasource.username=X
spring.datasource.password=X
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.hibernate.naming_strategy=my.package.CustomNamingStrategy
Run Code Online (Sandbox Code Playgroud)
从JPA 2.1开始,我应该可以使用这些javax.persistence.schema-generation.*属性,但是在我的application.properties中设置它们似乎没有任何效果.
我见过的例子是这样那丝了一大堆额外的豆子,但他们没有使用MySQL.无论如何,这样做需要我配置春天为我提供的许多选项.
我的目标是:
我不想:
Lib版本:
hibernate : 4.3.11.FINAL
spring framework : 4.2.5.RELEASE
spring-boot : 1.3.3.RELEASE
spring-data-jpa : 1.10.1.RELEASE // for querydsl 4 support
spring-data-commons: 1.12.1.RELEASE // for querydsl 4 support
Run Code Online (Sandbox Code Playgroud)
(使用gradle,而不是maven)
我有一个扩展的通用Spring Data存储库接口QuerydslBinderCustomizer,允许我自定义查询执行.我正在尝试将内置的基本相等性测试扩展到默认存储库实现中,以便我可以使用Spring Data REST执行其他查询操作.例如:
GET /api/persons?name=Joe%20Smith // This works by default
GET /api/persons?nameEndsWith=Smith // This requires custom parameter binding.
Run Code Online (Sandbox Code Playgroud)
我遇到的问题是我创建的实体路径的每个别名似乎都覆盖了前面的别名绑定.
@NoRepositoryBean
public interface BaseRepository<T, ID extends Serializable>
extends PagingAndSortingRepository<T, ID>, QueryDslPredicateExecutor<T>, QuerydslBinderCustomizer {
@Override
@SuppressWarnings("unchecked")
default void customize(QuerydslBindings bindings, EntityPath entityPath){
Class<T> model = entityPath.getType();
Path<T> root = entityPath.getRoot();
for (Field field: model.getDeclaredFields()){
if (field.isSynthetic()) continue;
Class<?> fieldType = field.getType();
if (fieldType.isAssignableFrom(String.class)){
// This binding works by itself, but not after the next one is added
bindings.bind(Expressions.stringPath(root, field.getName())) …Run Code Online (Sandbox Code Playgroud) spring-data ×10
java ×7
spring ×6
jpa ×4
spring-boot ×3
hibernate ×2
api ×1
java-ee ×1
querydsl ×1
rest ×1
retrofit ×1
spring-mvc ×1