Spring Data JPA使用复合主键

演示环境

MySQL 5.7

JDK1.8

spring-data-jpa 1.10.4.RELEASE

hibernate 5.1.2.Final

这里演示一个余额宝的例子,一个用户一天一条记录,表示一个用户一天的收益情况。其中,用户ID,日期是复合主键

项目总体结构如下:

图片[1]-Spring Data JPA使用复合主键-第五维

下面依次贴出源代码

pom.xml

  1. <project xmlns=“http://maven.apache.org/POM/4.0.0” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
  2. xsi:schemaLocation=“http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd”>
  3. <modelVersion>4.0.0</modelVersion>
  4. <groupId>com.pp.jpa</groupId>
  5. <artifactId>springdata-jpa</artifactId>
  6. <version>1.0.0</version>
  7. <packaging>jar</packaging>
  8. <name>springdata-jpa</name>
  9. <url>http://maven.apache.org</url>
  10. <properties>
  11. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  12. <maven.compiler.source>1.8</maven.compiler.source>
  13. <maven.compiler.target>1.8</maven.compiler.target>
  14. </properties>
  15. <dependencies>
  16. <dependency>
  17. <groupId>mysql</groupId>
  18. <artifactId>mysql-connector-java</artifactId>
  19. <version>5.1.40</version>
  20. </dependency>
  21. <dependency>
  22. <groupId>org.springframework.data</groupId>
  23. <artifactId>spring-data-jpa</artifactId>
  24. <version>1.10.4.RELEASE</version>
  25. </dependency>
  26. <dependency>
  27. <groupId>org.hibernate</groupId>
  28. <artifactId>hibernate-core</artifactId>
  29. <version>5.1.2.Final</version>
  30. </dependency>
  31. <dependency>
  32. <groupId>org.hibernate</groupId>
  33. <artifactId>hibernate-entitymanager</artifactId>
  34. <version>5.1.2.Final</version>
  35. </dependency>
  36. <dependency>
  37. <groupId>junit</groupId>
  38. <artifactId>junit</artifactId>
  39. <version>4.12</version>
  40. <scope>test</scope>
  41. </dependency>
  42. </dependencies>
  43. </project>

下面依次是Java源码

  1. package com.pp.jpa.config;
  2. import javax.persistence.EntityManagerFactory;
  3. import javax.sql.DataSource;
  4. import org.springframework.context.annotation.Bean;
  5. import org.springframework.context.annotation.Configuration;
  6. import org.springframework.orm.jpa.JpaTransactionManager;
  7. import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
  8. import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
  9. import org.springframework.transaction.PlatformTransactionManager;
  10. import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
  11. @Configuration
  12. public class JPAConfiguration {
  13. @Bean
  14. public DataSource createDataSource(){
  15. MysqlDataSource ds = new MysqlDataSource();
  16. ds.setURL(“jdbc:mysql://127.0.0.1:3306/jpa”);
  17. ds.setUser(“root”);
  18. ds.setPassword(“admin123”);
  19. return ds;
  20. }
  21. @Bean(name=“entityManagerFactory”)
  22. public EntityManagerFactory createEntityManagerFactory(DataSource dataSource){
  23. LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
  24. entityManagerFactory.setDataSource(dataSource);
  25. HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
  26. jpaVendorAdapter.setGenerateDdl(true);
  27. jpaVendorAdapter.setShowSql(true);
  28. entityManagerFactory.setPackagesToScan(“com.pp.jpa.entity”);
  29. entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter);
  30. entityManagerFactory.afterPropertiesSet();
  31. return entityManagerFactory.getObject();
  32. }
  33. @Bean(name=“transactionManager”)
  34. public PlatformTransactionManager createPlatformTransactionManager(EntityManagerFactory entityManagerFactory){
  35. JpaTransactionManager transactionManager = new JpaTransactionManager();
  36. transactionManager.setEntityManagerFactory(entityManagerFactory);
  37. return transactionManager;
  38. }
  39. }

 

  1. package com.pp.jpa.entity;
  2. import java.io.Serializable;
  3. import javax.persistence.Embeddable;
  4. /**
  5. * 主键
  6. * 代表复合主键的实体bean需要实现Serializable接口
  7. */
  8. @Embeddable
  9. public class UserFundPrimarykey implements Serializable {
  10. private static final long serialVersionUID = 1L;
  11. //用户ID
  12. private Integer userId;
  13. /**
  14. * 日期,格式yyyy-MM-dd
  15. */
  16. private String date;
  17. public UserFundPrimarykey() {}
  18. public UserFundPrimarykey(Integer userId, String date) {
  19. this.userId = userId;
  20. this.date = date;
  21. }
  22. public Integer getUserId() {
  23. return userId;
  24. }
  25. public void setUserId(Integer userId) {
  26. this.userId = userId;
  27. }
  28. public String getDate() {
  29. return date;
  30. }
  31. public void setDate(String date) {
  32. this.date = date;
  33. }
  34. @Override
  35. public String toString() {
  36. return “UserFundPrimarykey [userId=” + userId + “, date=” + date + “]”;
  37. }
  38. }

 

  1. package com.pp.jpa.entity;
  2. import java.math.BigDecimal;
  3. import javax.persistence.Column;
  4. import javax.persistence.EmbeddedId;
  5. import javax.persistence.Entity;
  6. import javax.persistence.Table;
  7. /**
  8. * 模拟一个余额宝的功能
  9. * 一条记录代表一个用户一天的收益信息(本金,利率,利息)
  10. */
  11. @Entity
  12. @Table(name = “user_funds”)
  13. public class UserFund {
  14. /**
  15. * 主键
  16. * 复合主键不能用@Id,需要用@EmbeddedId。插入数据的时候必须手工赋值
  17. */
  18. @EmbeddedId
  19. private UserFundPrimarykey userFundPK;
  20. //本金
  21. @Column(precision=18, scale=5)
  22. private BigDecimal principal;
  23. //利率(5%传0.05)
  24. @Column(precision=18, scale=5)
  25. private BigDecimal rate;
  26. /**
  27. * 当天收益(日利息=本金*利率/365)
  28. * 保留2位小数
  29. */
  30. @Column(precision=18, scale=2)
  31. private BigDecimal interest;
  32. public UserFundPrimarykey getUserFundPK() {
  33. return userFundPK;
  34. }
  35. public void setUserFundPK(UserFundPrimarykey userFundPK) {
  36. this.userFundPK = userFundPK;
  37. }
  38. public BigDecimal getPrincipal() {
  39. return principal;
  40. }
  41. public void setPrincipal(BigDecimal principal) {
  42. this.principal = principal;
  43. }
  44. public BigDecimal getRate() {
  45. return rate;
  46. }
  47. public void setRate(BigDecimal rate) {
  48. this.rate = rate;
  49. }
  50. public BigDecimal getInterest() {
  51. return interest;
  52. }
  53. public void setInterest(BigDecimal interest) {
  54. this.interest = interest;
  55. }
  56. @Override
  57. public String toString() {
  58. return “UserFund [userFundPK=” + userFundPK + “, principal=” + principal + “, rate=” + rate + “, interest=”
  59. + interest + “]”;
  60. }
  61. }

 

  1. package com.pp.repository;
  2. import org.springframework.data.repository.CrudRepository;
  3. import com.pp.jpa.entity.UserFund;
  4. import com.pp.jpa.entity.UserFundPrimarykey;
  5. public interface UserFundRepository extends CrudRepository<UserFund, UserFundPrimarykey> {
  6. }

启动类

  1. package com.pp.jpa;
  2. import java.math.BigDecimal;
  3. import java.math.RoundingMode;
  4. import org.springframework.context.annotation.AnnotationConfigApplicationContext;
  5. import org.springframework.context.annotation.ComponentScan;
  6. import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
  7. import org.springframework.transaction.annotation.EnableTransactionManagement;
  8. import com.pp.jpa.entity.UserFund;
  9. import com.pp.jpa.entity.UserFundPrimarykey;
  10. import com.pp.repository.UserFundRepository;
  11. @ComponentScan
  12. @EnableJpaRepositories(value=“com.pp”)
  13. @EnableTransactionManagement
  14. public class App {
  15. public static void main(String[] args) throws Exception {
  16. AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(App.class);
  17. UserFund uf1 = new UserFund();
  18. //必须手动设置主键
  19. uf1.setUserFundPK(new UserFundPrimarykey(1, “2017-07-01”));
  20. uf1.setRate(new BigDecimal(“0.041”));
  21. uf1.setPrincipal(new BigDecimal(“10000”));
  22. //截断,只保留两位小数
  23. uf1.setInterest(uf1.getRate().multiply(uf1.getPrincipal()).divide(new BigDecimal(“365”), 2, RoundingMode.DOWN));
  24. UserFund uf2 = new UserFund();
  25. //必须手动设置主键
  26. uf2.setUserFundPK(new UserFundPrimarykey(2, “2017-07-01”));
  27. uf2.setRate(new BigDecimal(“0.041”));
  28. uf2.setPrincipal(new BigDecimal(“20000”));
  29. //截断,只保留两位小数
  30. uf2.setInterest(uf2.getRate().multiply(uf2.getPrincipal()).divide(new BigDecimal(“365”), 2, RoundingMode.DOWN));
  31. UserFundRepository ur = context.getBean(UserFundRepository.class);
  32. ur.save(uf1);
  33. ur.save(uf2);
  34. ur.findAll().forEach(System.out::println);
  35. //查询用户ID=2,在2017-07-01这一天的收益
  36. System.out.println(ur.findOne(new UserFundPrimarykey(2, “2017-07-01”)));
  37. context.close();
  38. }
  39. }

 

一些注意事项和做法已经在备注中有写,大家模仿着写就OK了

直接运行main方法,控制台输出如下信息

  1. Hibernate: select userfund0_.date as date1_0_0_, userfund0_.userId as userId2_0_0_, userfund0_.interest as interest3_0_0_, userfund0_.principal as principa4_0_0_, userfund0_.rate as rate5_0_0_ from user_funds userfund0_ where userfund0_.date=? and userfund0_.userId=?
  2. Hibernate: insert into user_funds (interest, principal, rate, date, userId) values (?, ?, ?, ?, ?)
  3. Hibernate: select userfund0_.date as date1_0_0_, userfund0_.userId as userId2_0_0_, userfund0_.interest as interest3_0_0_, userfund0_.principal as principa4_0_0_, userfund0_.rate as rate5_0_0_ from user_funds userfund0_ where userfund0_.date=? and userfund0_.userId=?
  4. Hibernate: insert into user_funds (interest, principal, rate, date, userId) values (?, ?, ?, ?, ?)
  5. Hibernate: select userfund0_.date as date1_0_, userfund0_.userId as userId2_0_, userfund0_.interest as interest3_0_, userfund0_.principal as principa4_0_, userfund0_.rate as rate5_0_ from user_funds userfund0_
  6. UserFund [userFundPK=UserFundPrimarykey [userId=1, date=2017-07-01], principal=10000.00000, rate=0.04100, interest=1.12]
  7. UserFund [userFundPK=UserFundPrimarykey [userId=2, date=2017-07-01], principal=20000.00000, rate=0.04100, interest=2.24]
  8. Hibernate: select userfund0_.date as date1_0_0_, userfund0_.userId as userId2_0_0_, userfund0_.interest as interest3_0_0_, userfund0_.principal as principa4_0_0_, userfund0_.rate as rate5_0_0_ from user_funds userfund0_ where userfund0_.date=? and userfund0_.userId=?
  9. UserFund [userFundPK=UserFundPrimarykey [userId=2, date=2017-07-01], principal=20000.00000, rate=0.04100, interest=2.24]

查询数据库

select ** from user_funds;

图片[2]-Spring Data JPA使用复合主键-第五维

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享