diff --git a/orm-demos/jpa-demos/jpa-sample/pom.xml b/orm-demos/jpa-demos/jpa-sample/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..c57705dd8701724b2c6ce16012e2f9cd712bb4c0 --- /dev/null +++ b/orm-demos/jpa-demos/jpa-sample/pom.xml @@ -0,0 +1,41 @@ + + + + jpa-demos + com.gsean.demos + 1.0-SNAPSHOT + + 4.0.0 + + jpa-sample + + + 11 + 11 + + + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-web + + + mysql + mysql-connector-java + runtime + + + com.alibaba + fastjson + + + + \ No newline at end of file diff --git a/orm-demos/jpa-demos/jpa-sample/src/main/java/com/gsean/jpa/JpaSampleApp.java b/orm-demos/jpa-demos/jpa-sample/src/main/java/com/gsean/jpa/JpaSampleApp.java new file mode 100644 index 0000000000000000000000000000000000000000..92cbe745892d820c5939d1d5c07de2be92d32740 --- /dev/null +++ b/orm-demos/jpa-demos/jpa-sample/src/main/java/com/gsean/jpa/JpaSampleApp.java @@ -0,0 +1,20 @@ +package com.gsean.jpa; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; + +/** + * @ClassName JpaSampleApp + * @Description TODO + * @Author guocheng + * @Date 2021/11/4 22:37 + * @Version 1.0 + **/ +@SpringBootApplication +@EnableJpaAuditing +public class JpaSampleApp { + public static void main(String[] args) { + SpringApplication.run(JpaSampleApp.class,args); + } +} diff --git a/orm-demos/jpa-demos/jpa-sample/src/main/java/com/gsean/jpa/config/MyAuditorAware.java b/orm-demos/jpa-demos/jpa-sample/src/main/java/com/gsean/jpa/config/MyAuditorAware.java new file mode 100644 index 0000000000000000000000000000000000000000..c31dff1f6441fb60c5228a89790eb493dca13cf2 --- /dev/null +++ b/orm-demos/jpa-demos/jpa-sample/src/main/java/com/gsean/jpa/config/MyAuditorAware.java @@ -0,0 +1,21 @@ +package com.gsean.jpa.config; + +import org.springframework.data.domain.AuditorAware; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +/** + * @ClassName MyAuditorA + * @Description TODO + * @Author guocheng + * @Date 2021/11/7 22:10 + * @Version 1.0 + **/ +@Component +public class MyAuditorAware implements AuditorAware { + @Override + public Optional getCurrentAuditor() { + return Optional.ofNullable(1L); + } +} diff --git a/orm-demos/jpa-demos/jpa-sample/src/main/java/com/gsean/jpa/entity/Department.java b/orm-demos/jpa-demos/jpa-sample/src/main/java/com/gsean/jpa/entity/Department.java new file mode 100644 index 0000000000000000000000000000000000000000..18759a5d2a33fb42d16cd48f55402c2f8425fb89 --- /dev/null +++ b/orm-demos/jpa-demos/jpa-sample/src/main/java/com/gsean/jpa/entity/Department.java @@ -0,0 +1,58 @@ +package com.gsean.jpa.entity; + +import com.gsean.jpa.enums.Status; +import lombok.Data; +import lombok.experimental.Accessors; +import org.springframework.data.annotation.CreatedBy; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedBy; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import javax.persistence.*; +import java.io.Serializable; +import java.time.LocalDateTime; + +@Data +@Entity +@Table(name = "department") +@Accessors(chain = true) +@EntityListeners(AuditingEntityListener.class) +public class Department implements Serializable { + + @Id + @GeneratedValue(strategy=GenerationType.IDENTITY) + private Long id; + + private String name; + + @Column(name = "parent_id") + private Long parentId; + + @Column(name="status") + @Enumerated(value = EnumType.STRING) + private Status status; + + @Column(name="created_by") + @CreatedBy + private Long createdBy; + + @Column(name="last_modified_by") + @LastModifiedBy + private Long lastModifiedBy; + + @Column(name = "created_at") + @CreatedDate + private LocalDateTime createdAt; + + @Column(name = "lastModifiedAt") + @LastModifiedDate + private LocalDateTime lastModifiedAt; + + @Version + private Long version; + + + + +} diff --git a/orm-demos/jpa-demos/jpa-sample/src/main/java/com/gsean/jpa/enums/Status.java b/orm-demos/jpa-demos/jpa-sample/src/main/java/com/gsean/jpa/enums/Status.java new file mode 100644 index 0000000000000000000000000000000000000000..64435045029cc49915312cbaad36d7555293e9aa --- /dev/null +++ b/orm-demos/jpa-demos/jpa-sample/src/main/java/com/gsean/jpa/enums/Status.java @@ -0,0 +1,13 @@ +package com.gsean.jpa.enums; + +public enum Status { + + ACTIVE("可用"), + UNACTIVE("不可用"); + + private String des; + + Status(String des) { + this.des = des; + } +} diff --git a/orm-demos/jpa-demos/jpa-sample/src/main/java/com/gsean/jpa/enums/StatusV2.java b/orm-demos/jpa-demos/jpa-sample/src/main/java/com/gsean/jpa/enums/StatusV2.java new file mode 100644 index 0000000000000000000000000000000000000000..26a0273ef74dbbccda56df3fca43981ff6c20d85 --- /dev/null +++ b/orm-demos/jpa-demos/jpa-sample/src/main/java/com/gsean/jpa/enums/StatusV2.java @@ -0,0 +1,38 @@ +package com.gsean.jpa.enums; + +import java.util.Objects; + +public enum StatusV2 { + ACTIVE(1,"可用"), + UNACTIVE(2,"不可用"); + + private Integer code; + private String des; + + StatusV2(Integer code,String des) { + this.code=code; + this.des = des; + } + + public Integer getCode() { + return code; + } + + public String getDes() { + return des; + } + + //获取枚举实例 + public static StatusV2 fromValue(Integer value) { + for (StatusV2 statusEnum : StatusV2.values()) { + if (Objects.equals(value, statusEnum.getCode())) { + return statusEnum; + } + } + throw new IllegalArgumentException(); + } + + public static void main(String[] args) { + System.out.println(StatusV2.ACTIVE.getCode()); + } +} diff --git a/orm-demos/jpa-demos/jpa-sample/src/main/java/com/gsean/jpa/enums/StatusV2Converter.java b/orm-demos/jpa-demos/jpa-sample/src/main/java/com/gsean/jpa/enums/StatusV2Converter.java new file mode 100644 index 0000000000000000000000000000000000000000..45ff50e207c5ae646941b02f4d3174d6bc94b016 --- /dev/null +++ b/orm-demos/jpa-demos/jpa-sample/src/main/java/com/gsean/jpa/enums/StatusV2Converter.java @@ -0,0 +1,23 @@ +package com.gsean.jpa.enums; + +import javax.persistence.AttributeConverter; + +/** + * @ClassName StatusV2Converter + * @Description TODO + * @Author guocheng + * @Date 2021/11/5 22:09 + * @Version 1.0 + **/ +public class StatusV2Converter implements AttributeConverter { + @Override + public Integer convertToDatabaseColumn(StatusV2 statusV2) { + return statusV2.getCode(); + } + + @Override + public StatusV2 convertToEntityAttribute(Integer code) { + return StatusV2.fromValue(code); + + } +} diff --git a/orm-demos/jpa-demos/jpa-sample/src/main/java/com/gsean/jpa/repository/DepartmentDao.java b/orm-demos/jpa-demos/jpa-sample/src/main/java/com/gsean/jpa/repository/DepartmentDao.java new file mode 100644 index 0000000000000000000000000000000000000000..e12377471122b6cf5455a895bb5e6f0bdf81c1d8 --- /dev/null +++ b/orm-demos/jpa-demos/jpa-sample/src/main/java/com/gsean/jpa/repository/DepartmentDao.java @@ -0,0 +1,7 @@ +package com.gsean.jpa.repository; + +import com.gsean.jpa.entity.Department; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface DepartmentDao extends JpaRepository { +} diff --git a/orm-demos/jpa-demos/jpa-sample/src/main/resources/application.yml b/orm-demos/jpa-demos/jpa-sample/src/main/resources/application.yml new file mode 100644 index 0000000000000000000000000000000000000000..681dddf2fa29d744f39c08cf64bce5d580fa2a33 --- /dev/null +++ b/orm-demos/jpa-demos/jpa-sample/src/main/resources/application.yml @@ -0,0 +1,18 @@ +server: + port: 8082 + + +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://localhost:3306/jpa_test + username: root + password: 123456 + jpa: + show-sql: true + properties.hibernate.format_sql: true + + +logging: + level: + org.hibernate.type.descriptor.sql.BasicBinder: trace \ No newline at end of file diff --git a/orm-demos/jpa-demos/jpa-sample/src/main/resources/sql/department.sql b/orm-demos/jpa-demos/jpa-sample/src/main/resources/sql/department.sql new file mode 100644 index 0000000000000000000000000000000000000000..f7cdf7428703a8bf450b9d82e9e403961aca3ecc --- /dev/null +++ b/orm-demos/jpa-demos/jpa-sample/src/main/resources/sql/department.sql @@ -0,0 +1,37 @@ +/* + Navicat Premium Data Transfer + + Source Server : local + Source Server Type : MySQL + Source Server Version : 80022 + Source Host : localhost:3306 + Source Schema : jpa_test + + Target Server Type : MySQL + Target Server Version : 80022 + File Encoding : 65001 + + Date: 07/11/2021 23:31:57 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for department +-- ---------------------------- +DROP TABLE IF EXISTS `department`; +CREATE TABLE `department` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + `parent_id` bigint unsigned NOT NULL, + `status` varchar(10) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL, + `created_by` bigint NOT NULL COMMENT '创建人', + `last_modified_by` bigint NOT NULL COMMENT '最后更改人', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `last_modified_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间', + `version` bigint NOT NULL COMMENT '版本', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/orm-demos/jpa-demos/jpa-sample/src/test/java/com/gsean/jpa/JpaSampleAppTest.java b/orm-demos/jpa-demos/jpa-sample/src/test/java/com/gsean/jpa/JpaSampleAppTest.java new file mode 100644 index 0000000000000000000000000000000000000000..78272b8dbaae7322d7b0d8386e31854f62378c8e --- /dev/null +++ b/orm-demos/jpa-demos/jpa-sample/src/test/java/com/gsean/jpa/JpaSampleAppTest.java @@ -0,0 +1,137 @@ +package com.gsean.jpa; + +import com.alibaba.fastjson.JSON; +import com.gsean.jpa.entity.Department; +import com.gsean.jpa.enums.Status; +import com.gsean.jpa.repository.DepartmentDao; +import org.hamcrest.Matchers; +import org.junit.Assert; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.domain.Example; +import org.springframework.data.domain.ExampleMatcher; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.List; + +@SpringBootTest +class JpaSampleAppTest { + + private static final Long AUDITOR_ID=1L; + private static final String DEPT_NAME="技术部"; + private static final String UPDATE_DEPT_NAME="管理部"; + + @Autowired + private DepartmentDao departmentDao; + + private Department department; + + @BeforeEach + public void init(){ + createDept(); + } + + private void createDept(){ + department=new Department(); + department.setName(DEPT_NAME).setParentId(2L); + } + + + + @Test + @DisplayName("缺省插入") + public void testA(){ + Department addDepartment = new Department(); + addDepartment.setName("test").setParentId(2L).setStatus(Status.ACTIVE); + Department redepartment=departmentDao.saveAndFlush(addDepartment); + System.out.println(addDepartment); + } + + + @Test + @DisplayName("审计测试") + @Transactional + public void testB(){ + LocalDateTime nowTime = LocalDateTime.now(); + System.out.println("当前时间:"+nowTime); + long beforeCount = departmentDao.count(); + departmentDao.saveAndFlush(department); + System.out.println(JSON.toJSONString(department)); + long afterCount = departmentDao.count(); + Assert.assertTrue(afterCount==beforeCount+1); + Assert.assertEquals(AUDITOR_ID,department.getCreatedBy()); + Assert.assertEquals(AUDITOR_ID,department.getLastModifiedBy()); + Assert.assertThat(department.getCreatedAt(), Matchers.greaterThan(nowTime)); + } + + @Test + @DisplayName("更新审计时间测试") + @Transactional + public void testB1() throws Exception{ + LocalDateTime nowTime = LocalDateTime.now(); + System.out.println("当前时间:"+nowTime); + long beforeCount = departmentDao.count(); + departmentDao.saveAndFlush(department); + System.out.println("插入数据:"+JSON.toJSONString(department)); + long afterCount = departmentDao.count(); + Assert.assertTrue(afterCount==beforeCount+1); + Assert.assertEquals(DEPT_NAME,department.getName()); + LocalDateTime lastModifiedAt = department.getLastModifiedAt(); + Thread.sleep(2000); + department.setName(UPDATE_DEPT_NAME); + departmentDao.saveAndFlush(department); + System.out.println("更新后数据:"+JSON.toJSONString(department)); + Assert.assertEquals(UPDATE_DEPT_NAME,department.getName()); + Assert.assertThat(department.getLastModifiedAt(), Matchers.not(lastModifiedAt)); + } + + @Test + @DisplayName("乐观锁测试") + @Transactional + public void testC(){ + long beforeCount = departmentDao.count(); + departmentDao.saveAndFlush(department); + System.out.println("插入数据:"+JSON.toJSONString(department)); + long afterCount = departmentDao.count(); + Assert.assertTrue(afterCount==beforeCount+1); + Long initVersion = department.getVersion(); + Assert.assertNotNull(initVersion); + department.setName(UPDATE_DEPT_NAME); + departmentDao.saveAndFlush(department); + System.out.println("更新后数据:"+JSON.toJSONString(department)); + Assert.assertTrue(UPDATE_DEPT_NAME.equals(department.getName())); + Assert.assertTrue(department.getVersion()==initVersion+1); + } + + + @Test + @DisplayName("QBE查询测试") + @Transactional + public void testD(){ + Department dept01 = new Department().setName("dept01").setStatus(Status.ACTIVE).setParentId(1L); + Department dept02 = new Department().setName("dept02").setStatus(Status.ACTIVE).setParentId(1L); + Department dept03 = new Department().setName("dept03").setStatus(Status.UNACTIVE).setParentId(1L); + List departments = Arrays.asList(dept01, dept02, dept03); + departmentDao.saveAll(departments); + List departmentList = departmentDao.findAll(); + System.out.println("所有部门:"+JSON.toJSONString(departmentList)); + + Department qDept=new Department().setName("dept"); + ExampleMatcher matcher = ExampleMatcher.matching() + .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.startsWith()); + Example departmentExample = Example.of(qDept, matcher); + List exampleAll = departmentDao.findAll(departmentExample); + System.out.println("匹配查询部门:"+JSON.toJSONString(departmentList)); + Assert.assertTrue(exampleAll.size()==3); + + + } + + + +} \ No newline at end of file diff --git a/orm-demos/jpa-demos/pom.xml b/orm-demos/jpa-demos/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..3621282e58333a37da73d34020cd878e9ab0533f --- /dev/null +++ b/orm-demos/jpa-demos/pom.xml @@ -0,0 +1,23 @@ + + + + orm-demos + com.gsean.demos + 1.0-SNAPSHOT + + 4.0.0 + + jpa-demos + pom + + jpa-sample + + + + 11 + 11 + + + \ No newline at end of file diff --git a/orm-demos/pom.xml b/orm-demos/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..e114b65e7c75ed870379501575df2e175bdc4071 --- /dev/null +++ b/orm-demos/pom.xml @@ -0,0 +1,23 @@ + + + + gsean-springboot-demos + com.gsean.demos + 1.0-SNAPSHOT + + 4.0.0 + + orm-demos + pom + + jpa-demos + + + + 11 + 11 + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index b60701783ccedbe48244e02572eb40915ae08bbb..54f4e9ceaf1cdfe2c6e9fcd641d89617c06be8f8 100644 --- a/pom.xml +++ b/pom.xml @@ -38,6 +38,7 @@ docker-demos git-demos mongodb-demes + orm-demos