SpringBoot 整合 Hibernate 注解配置 (非 JPA)

SpringBoot 整合 Hibernate

最近和同事一起开发一个 SpringBoot + Hibernate + Vue 的进销存管理系统(https://github.com/pss-dev/pss) 遇到了一个问题, 项目基础架构使用 SpringBoot 开发, 但是 ORM 框架在讨论后选择了 Hibernate 而不是 Mybatis, 所以帅帅我本着认真负责的态度就先网上看了看 SpringBoot 与 Hibernate 的整合, 最后发现网上所谓的 SpringBoot 整合 Hibernate 都是打着 Hibernate 的幌子, 最后整合的是 Hibernate-Jpa, 底层写的都是 jpa 的代码, 然后帅帅就又开始自己研究了, 于是乎也就有个这篇博文和大家分享.

file

PS: 还记得学习 Java SE 到 GUI 部分的时候老师说这玩意没人用, 我们不讲, emmm… 奈何这周工作中需要维护一个老旧项目, 帅帅我的心情十分沉重, 在 Java GUI 里面遨游的时候, 那个心情…此处省略一万字…, But, But, But, 到最后发现, 我 TM 竟然觉得 Java GUI 还挺有意思的.

file

所以本来打算出一篇 Java GUI 的文章, 然后给我们的项目Angboot: https://github.com/DreamLi1314/angboot 添加 GUI 支持.

file

奈何这周比较忙(谋划一件大事, 后边再告诉你哦), 所以下篇分享一些 Java GUI 的东东, 虽然比较基础和老旧, 但是帅帅觉得其实还是有点用的, 可以自己玩玩做一些东西, 比如帅帅大学学 Oracle 的时候觉得 Oracle 的客户端 PL/SQL 特别慢, 卡(电脑不行, 软件功能多), 因此就用 Java GUI 自己写一了一个 Oracle Client, 比较简洁和快速, 满足开始学习时 SQL 的执行和 Result 的显示.

PS: 听过一个程序员对疫情居家隔离的总结 ----- 疫情居家隔离的开始, 也是你进入 BAT 最好的时机.

另外还有朋友对我说过一句话 ----- 虽然受疫情影响, 大部分公司都不涨工资了, 但是你可以换一个工资高的公司啊

帅帅我是很惭愧的, 所以最近开始认真着手准备一个系列博文 ---- <<面向面试官编程>>系列, 一方面对自己知识的梳理, 另一方变也希望对大家面试, 跳槽有所帮助.(如果帮到您, 记得回来请我喝咖啡哦…哈哈…)

好了, 废话少说, 开始本文的重点: SpringBoot 整合 Hibernate (扯了半天皮, 文章主题没忘吧? 罒ω罒)

file


1. 配置 SessionFactory

package com.pssdev.pss.config;

@Configuration
// 读取 application.yml/properties 文件中以 `pss.hibernate` 开头的配置并映射到 class 属性
@ConfigurationProperties(prefix = "pss.hibernate")
public class SessionFactoryConfig {

	 // 注入数据源, 帅帅使用的 Druid
   @Autowired
   public SessionFactoryConfig(DataSource dataSource) {
      this.dataSource = dataSource;
   }

   @Bean("sessionFactory")
   public LocalSessionFactoryBean getSessionFactory() throws IOException {
      LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
      localSessionFactoryBean.setDataSource(dataSource); // 配置数据源
			// 如果使用 xml 配置则使用该方法进行包扫描
//      PathMatchingResourcePatternResolver pmprpr = new PathMatchingResourcePatternResolver();
//      Resource[] resource = pmprpr.getResources("classpath*:com/pssdev/pss/**/domain/*.hbm.xml");
//      localSessionFactoryBean.setMappingLocations(resource);

      // 现在配置基本都切换到 java config, 帅帅也是, 所以使用 AnnotatedPackages
      localSessionFactoryBean.setAnnotatedPackages("classpath*:com/pssdev/pss/entity");
			// 添加 Hibernate 配置规则
      Properties hibernateProperties = new Properties();
      hibernateProperties.put("hibernate.dialect",dialect);
      hibernateProperties.put("current_session_context_class", sessionContextClass);
      hibernateProperties.put("hibernate.show_sql", showSql);
      hibernateProperties.put("hibernate.format_sql", formatSql);
      hibernateProperties.put("hibernate.hbm2ddl.auto", ddlAuto);
      localSessionFactoryBean.setHibernateProperties(hibernateProperties);
      localSessionFactoryBean.setPackagesToScan("com.pssdev.pss.entity");

      return localSessionFactoryBean;
   }

   ...getter and setter

   private String dialect;
   private String sessionContextClass;
   private boolean showSql;
   private boolean formatSql;
   private String ddlAuto;

   private final DataSource dataSource;
}
  • application.yml
# Hibernate config
pss:
   hibernate:
      ddl-auto: update
      dialect: org.hibernate.dialect.H2Dialect
      session-context-class: org.springframework.orm.hibernate5.SpringSessionContext
      formatSql: true
      show-sql: true

2. 配置事务 TransactionConfig

package com.pssdev.pss.config;

@Configuration
public class TransactionConfig implements TransactionManagementConfigurer {

   @Autowired
   public TransactionConfig(SessionFactory sessionFactory) {
      this.sessionFactory = sessionFactory;
   }

    // 事务管理交给 HibernateTransactionManager 
   @Bean("transactionManager")
   public HibernateTransactionManager getTransactionManager(){
      HibernateTransactionManager hibernateTransactionManager = new HibernateTransactionManager();
      hibernateTransactionManager.setSessionFactory(sessionFactory);

      return hibernateTransactionManager;
   }

   @Override
   public PlatformTransactionManager annotationDrivenTransactionManager() {
      return getTransactionManager();
   }

   private final SessionFactory sessionFactory;
}

3. 排除 Jpa 自动配置

package com.pssdev.pss;

// 排除 DataSource, jpa, HibernateJpa 的自动配置
@SpringBootApplication(exclude = {
   DataSourceAutoConfiguration.class,
   JpaRepositoriesAutoConfiguration.class,
   HibernateJpaAutoConfiguration.class })
// 开启事务管理
@EnableTransactionManagement(proxyTargetClass = true)
public class PssApplication {

   public static void main(String[] args) {
      SpringApplication.run(PssApplication.class, args);
   }

}

4. 应用

4.1 添加 department entity 完成一对多映射

package com.pssdev.pss.entity;

@Entity(name = "t_dept")
public class Department implements Serializable {
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private Integer id;
   @Column
   private String name;
   @Column
   private String initials;

   // 多对一映射
   @ManyToOne
   @JoinColumn(name = "parent_id")
   private Department parent;

   // 一对多映射
   @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
   private Set<Department> children = new HashSet<>();

   public Department() {
   }

   public Department(Integer id) {
      this.id = id;
   }

   public Integer getId() {
      return id;
   }

   public void setId(Integer id) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public String getInitials() {
      return initials;
   }

   public void setInitials(String initials) {
      this.initials = initials;
   }

   public Set<Department> getChildren() {
      return children;
   }

   public void setChildren(Set<Department> children) {
      this.children = children;
   }

   public Department getParent() {
      return parent;
   }

   public void setParent(Department parent) {
      this.parent = parent;
   }

   @Override
   public String toString() {
      return "Department{" +
         "id=" + id +
         ", name='" + name + '\'' +
         ", initials='" + initials + '\'' +
         ", parent=" + (parent != null ? parent.id : null) +
         ", children=[" + (children != null
            ? children.stream().map(d -> d.id + "").collect(Collectors.joining(","))
            : null)
         + "]}";
   }
}

4.2 DepartmentService

package com.pssdev.pss.service.impl;

@Service("departmentService")
public class DepartmentServiceImpl implements DepartmentService {

   @Autowired
   public DepartmentServiceImpl(DepartmentDao departmentDao) {
      this.departmentDao = departmentDao;
   }

   @Transactional(readOnly = true)
   @Override
   public Department getDepartment(Integer parentId) {
      return departmentDao.getDepartment(parentId);
   }

   @Transactional(readOnly = true)
   @Override
   public List<Department> getDepartments(Integer parentId) {
      return parentId == null
         ? departmentDao.getAllDepartments()
         : Arrays.asList(departmentDao.getDepartment(parentId));
   }

   @Transactional(readOnly = true)
   @Override
   public List<Department> getDepartments() {
      return departmentDao.getAllDepartments();
   }

   @Transactional
   @Override
   public int insertDepartment(Department department) {
      return departmentDao.insertDepartment(department);
   }

   @Transactional
   @Override
   public void updateDepartment(Department department) {
      departmentDao.updateDepartment(department);
   }

   @Transactional
   @Override
   public void deleteDepartment(Integer id) {
      departmentDao.deleteDepartment(id);
   }

   private final DepartmentDao departmentDao;
}

对于 Get 操作我们事务管理标注 readOnly=true

4.3 DepartmentDao

package com.pssdev.pss.dao.impl;

@Repository("departmentDao")
public class DepartmentDaoImpl extends BaseDao implements DepartmentDao {
   @Override
   public List<Department> getAllDepartments() {
      Session session = getSession();

      CriteriaQuery<Department> query = session.getCriteriaBuilder()
         .createQuery(Department.class);
      query.from(Department.class);

      return session.createQuery(query).list();
   }

   @Override
   public Integer insertDepartment(Department department) {
      Session session = getSession();

      return (Integer) session.save(department); // 用 save
   }

   @Override
   public Department getDepartment(Integer parentId) {
      return getSession().find(Department.class, parentId); // 用 find 而不是 load
   }

   @Override
   public void deleteDepartment(Integer id) {
      Department department = getDepartment(id);

      if(department != null) {
         getSession().delete(department); // 用 delete, 而不是 remove
      }
   }

   @Override
   public void updateDepartment(Department department) {
      getSession().update(department);
   }
}

5. 测试

测试框架用的是 Junit5 — jupiter 测试框架

package com.pssdev.pss.service;

@SpringBootTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class DepartmentServiceTests {

   @Autowired
   private DepartmentService departmentService;

   @Test
   @Order(1)
   public void testNonNull() {
      Assertions.assertNotNull(departmentService, "Init Department Dao Error.");
   }

   @Order(2)
   @RepeatedTest(value = 5, name = "Insert 5 dept to make sure get dept id not null")
   public void testInsertTopDepartment() {
      int index = (int) (1000 * Math.random());
      Department dept1 = new Department();
      dept1.setName("Top Level" + index);
      dept1.setInitials("TL" + index);

      departmentService.insertDepartment(dept1);
   }

   @Test
   @Order(3)
   public void testGetDepartments() {
      List<Department> departments = departmentService.getDepartments();

      Assertions.assertNotNull(departments, "Departments is empty");
   }

   @ParameterizedTest
   @ValueSource(ints = {2})
   @Order(4)
   public void testGetDepartment(int id) {
      Department department = departmentService.getDepartment(id);

      Assertions.assertNotNull(department, "Department is null");
      Assertions.assertEquals(department.getId(), id, "Get department error.");

      LOGGER.info("Department: {}", department);
   }

   @ParameterizedTest
   @ValueSource(ints = {2})
   @Order(5)
   public void testInsertChildDepartment(int id) {
      Department parentDept = departmentService.getDepartment(id);

      LOGGER.info("Query parent dept first: {}", parentDept);

      Department cDept1 = new Department();
      cDept1.setName("Child Level1");
      cDept1.setInitials("CL1");
      cDept1.setParent(parentDept);

      Department cDept2 = new Department();
      cDept2.setName("Child Level2");
      cDept2.setInitials("CL2");
      cDept2.setParent(parentDept);

      // insert children
      int cid1 = departmentService.insertDepartment(cDept1);
      int cid2 = departmentService.insertDepartment(cDept2);

      LOGGER.info("Insert dept {}, {}.", cid1, cid2);

      // get parent again
      parentDept = departmentService.getDepartment(id);

      LOGGER.info("Query parent dept again: {}", parentDept);

      Set<Department> children = parentDept.getChildren();

      Assertions.assertFalse(
         children == null || children.size() < 1, "Query children error.");

      Set<Integer> childIds = children.stream().map(d -> d.getId()).collect(Collectors.toSet());

      Assertions.assertTrue(childIds.contains(cid1), "Missing child 1");
      Assertions.assertTrue(childIds.contains(cid2), "Missing child 2");
   }

   @ParameterizedTest
   @ValueSource(ints = 2)
   @Order(6)
   public void testDeleteDepartment(int id) {
      departmentService.deleteDepartment(id);
   }

   private static final Logger LOGGER
      = LoggerFactory.getLogger(DepartmentServiceTests.class);
}

file
在这里插入图片描述

在这里插入图片描述

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
要将Spring BootJPA整合,首先需要在pom.xml文件中添加相应的依赖。这些依赖包括Spring Data JPA和MySQL驱动。例如,在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> ``` 接下来,你需要在Spring Boot应用程序的配置文件中添加数据库连接配置。你可以在application.properties或application.yml文件中添加以下配置: ```yaml spring.datasource.url=jdbc:mysql://localhost:3306/your_database_name spring.datasource.username=your_username spring.datasource.password=your_password spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=update ``` 在这个配置中,你需要将`your_database_name`替换为你的数据库名称,`your_username`替换为你的数据库用户名,`your_password`替换为你的数据库密码。 然后,你可以创建实体类和存储库接口。实体类用于映射数据库表,而存储库接口用于定义对数据库的操作。可以使用`@Entity`和`@Table`注解来标识实体类使用`@Repository`或`@RepositoryRestResource`注解来标识存储库接口。 最后,你可以在Spring Boot应用程序的启动类上添加`@EnableJpaRepositories`注解,以启用JPA存储库。 以上是将Spring BootJPA整合的基本步骤。通过这种方式,你可以使用JPA进行数据库操作,并且Spring Boot会自动为你处理大部分的配置和实现。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [springboot整合jpa,步骤详细(图文结合讲解)](https://blog.csdn.net/weixin_43442127/article/details/119953836)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [springboot整合JPA](https://blog.csdn.net/weixin_44740485/article/details/124904112)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值