Here I just built a very simple example based on the previous JPA example. It is recommended to go through the previous JPA example first before checking on this example. The source code of the updated example can be found at github.
To make it even simpler, I changed the JPA provider to hibernate as it seems hibernate works better with Spring than Eclipselink. I had to admit I encountered some weird errors when building this example with Eclipselink. It appears that Eclipselink is more strict or less error tolerant when it comes to JPQL.
We need an updated beans.xml to enable spring data for JPA. The following is the updated beans.xml file. Please note the bold font in it.
[beans.xml]
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd "> <!-- the base package for spring data jpa repository interfaces --> <jpa:repositories base-package="com.mytechtip.example.springjpatest.repository" /> <!-- Enable the component scan (auto wiring etc) for the following package --> <context:component-scan base-package="com.mytechtip.example.springjpatest" /> <!-- Make sure the following is specified to enable transaction --> <tx:annotation-driven /> <bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> <!-- This defines the entity manager factory with some custom properties --> <bean id='entityManagerFactory' class='org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean'> <property name="persistenceUnitName" value="spring-jpa-test"/> <property name='dataSource' ref='dataSource' /> </bean> <!-- This defines the hsqldb data source --> <bean id='dataSource' class='org.springframework.jdbc.datasource.DriverManagerDataSource'> <property name='driverClassName' value='org.hsqldb.jdbc.JDBCDriver' /> <property name='url' value='jdbc:hsqldb:file:spring_jpa_test_db' /> <property name='username' value='sa' /> <property name='password' value='' /> </bean> </beans>
Then we just create the very simple JPA repository interface in the above mentioned base package as follows:
[UserRepository.java]
package com.mytechtip.example.springjpatest.repository; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import com.mytechtip.example.springjpatest.User; public interface UserRepository extends JpaRepository<User, Long> { List<User> getNameStartsWith(String prefix); }
We need to update the User class to add the named query which should have the same name defined in the above repository interface.
[User.java]
package com.mytechtip.example.springjpatest; import java.io.Serializable; import java.lang.String; import java.util.Date; import javax.persistence.*; /** * Entity implementation class for Entity: User * */ @Entity @Table(name="user") @NamedQueries({ @NamedQuery(name="User.getNameStartsWith", query="select u from User u where u.name LIKE ? order by u.name") }) public class User implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; private String name; private String address; @Temporal(TemporalType.DATE) private Date dob; public User() { super(); } public Long getId() { return this.id; } public void setId(Long id) { this.id = id; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public String getAddress() { return this.address; } public void setAddress(String address) { this.address = address; } public Date getDob() { return this.dob; } public void setDob(Date dob) { this.dob = dob; } }
An abstract user data access object has been extracted so I can have different implementation versions of DAO (the plain old one and the one using new spring data). The following is the implementation based on Spring Data.
[UserDaoRepo.java]
package com.mytechtip.example.springjpatest; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; import com.mytechtip.example.springjpatest.repository.UserRepository; @Repository public class UserDaoRepo extends AbstractUserDao { private static final int ONE_YEAR = 1000 * 60 * 60 * 24 * 365; @Autowired UserRepository userRepository; @Transactional public User save(User u) { // some business logic if (u.getName()==null) { throw new IllegalArgumentException("Name can not be null"); } if (u.getDob()==null) { throw new IllegalArgumentException("Dob can not be null"); } if ((System.currentTimeMillis()-u.getDob().getTime())< 10 * ONE_YEAR) { throw new IllegalArgumentException("Must be 10+ year older"); } return userRepository.save(u); } @Transactional public List<User> getNameStartsWith(String namePrefix) { // use the spring data jpa repository return userRepository.getNameStartsWith(namePrefix+"%"); } }
Then just update the Main class to use the UserDataRepo to run the simple example.
As mentioned above, the updated code is available from github if you want to try it yourself.
No comments:
Post a Comment