前言
Hibernate是一个对象/关系映射(ORM)解决方案,适用于用Java和其他JVM语言编写的程序。 虽然使用Hibernate不需要很强的SQL背景,但对其概念的基本理解是有用的——尤其是数据建模的原理。了解事务和设计模式(如工作单元)的基础知识也很重要。
Hibernate是一个全自动的ORM框架。ORM框架通过其独特的优势,可以简化开发、提高可维护性、跨数据库支持和提高性能等。为开发者节约大量的时间。
Hibernate 的主要功能
1.对象关系映射(ORM):Hibernate可以自动将Java类和对象映射到关系数据库中的表和行。
2.透明持久性:Hibernate可以自动管理对象的生命周期,并将其持久化到数据库中,从而使开发人员可以专注于业务逻辑,而不必担心对象的状态管理。
3.查询语言:Hibernate提供了一种基于面向对象的查询语言(HQL),使开发人员可以使用面向对象的方式来查询和操作数据库。
4.缓存管理:Hibernate提供了一个高效的缓存管理机制,可以提高应用程序的性能。
5.事务管理:Hibernate可以自动管理数据库事务,从而确保数据的完整性和一致性。
使用Hibernate的好处
1.简化数据访问层:Hibernate简化了数据访问层的开发,开发人员只需要关注业务逻辑,而不必编写繁琐的SQL语句。
2.提高开发效率:Hibernate可以自动生成数据库表和列,省去了手动创建和维护数据库表的麻烦。此外,Hibernate还提供了一种基于对象的查询语言,使得查询和操作数据变得更加简单。
3.提高可维护性:Hibernate使得应用程序的代码更加清晰、简单易懂,使得应用程序更加易于维护。
4.支持多种数据库:Hibernate可以很方便地支持多种关系数据库,包括MySQL、Oracle、Microsoft SQL Server等。
5.提高性能:Hibernate提供了一个缓存机制,可以提高应用程序的性能。此外,Hibernate还支持批量处理和延迟加载等优化技术,可以进一步提高应用程序的性能。
6.支持事务管理:Hibernate可以自动管理数据库事务,从而确保数据的完整性和一致性。开发人员可以专注于业务逻辑,而不必手动处理事务。
开始前
启动MySQL服务,创建demo需要的表。
sql
代码解读
复制代码
use demo CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(128) NOT NULL DEFAULT '' COMMENT '用户名', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
用https://start.spring.io/
初始化springboot项目
我自己比较喜欢的项目结构
text
代码解读
复制代码
--- |-api // 对外接口,controller |-dto // 对外传输实体 |-domain // 领域 |-entity // 领域对象 |-repository // 仓储,数据存储与获取 |-service // 领域服务
Maven 依赖
Hibernate作为ORM框架,它可以替代JdbcTemplate,但Hibernate仍然需要JDBC驱动,所以,我们需要引入JDBC驱动、连接池,以及Hibernate本身。在Maven中,我们加入以下依赖项:
xml
代码解读
复制代码
<properties> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>17</java.version> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <mysql.version>8.0.28</mysql.version> <druid.version>1.1.21</druid.version> <hibernate.version>6.6.0.Final</hibernate.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>${druid.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.hibernate.orm</groupId> <artifactId>hibernate-core</artifactId> <version>${hibernate.version}</version> </dependency> </dependencies>
配置
application.properties
整理了一份好像面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题
需要全套面试笔记【点击此处即可】免费获取
text
代码解读
复制代码
spring.application.name=hibernate-demo server.port=8081 spring.datasource.url=jdbc:mysql://localhost:3306/demo spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.connection.autocommit=true # 显示SQL并格式化SQL spring.jpa.properties.hibernate.show_sql=true spring.jpa.properties.hibernate.format_sql=true
jpa 配置
在JpaConfig
中,我们仍然需要引入JDBC配置文件,声明repository的位置,以及启用声明式事务。
为了启用Hibernate,还需要创建一个LocalSessionFactoryBean。
HibernateTransactionManager 是配合Hibernate使用声明式事务所必须的。
java
代码解读
复制代码
package com.zxy.demo.hibernate; import java.util.Map; import java.util.Properties; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import org.springframework.transaction.PlatformTransactionManager; import jakarta.persistence.EntityManagerFactory; @Configuration @EnableJpaRepositories( entityManagerFactoryRef = "dbEntityManagerFactory", transactionManagerRef = "dbTransactionManager", basePackages = {"com.zxy.demo.hibernate.domain.repository" } ) public class JpaConfig { @Autowired private DataSource dataSource; @Autowired private JpaProperties jpaProperties; @Bean(name = "dbEntityManagerFactory") public LocalContainerEntityManagerFactoryBean entityManagerFactory() { LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(dataSource); // 设置实体类的包路径 em.setPackagesToScan("com.zxy.demo.hibernate.domain.entity"); HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); em.setJpaVendorAdapter(vendorAdapter); // https://github.com/spring-projects/spring-boot/issues/39753 em.setEntityManagerFactoryInterface(EntityManagerFactory.class); em.setJpaProperties(hibernateProperties()); return em; } private Properties hibernateProperties() { Properties properties = new Properties(); for (Map.Entry<String, String> entry : jpaProperties.getProperties().entrySet()) { properties.put(entry.getKey(), entry.getValue()); } return properties; } @Bean(name = "dbTransactionManager") public PlatformTransactionManager transactionManager(LocalContainerEntityManagerFactoryBean entityManagerFactory) { return new JpaTransactionManager(entityManagerFactory.getObject()); } }
Entity
对应数据库表对象。
id
是自增主键,
这种映射关系十分易懂,但我们需要添加一些注解来告诉Hibernate如何把User类映射到表记录,
防止表名映射错误,可以追加一个@Table(name="user")
表示,
每个属性到数据库列的映射用@Column()
标识,nullable
指示列是否允许为NULL,updatable
指示该列是否允许被用在UPDATE语句,length
指示String类型的列的长度。
java
代码解读
复制代码
package com.zxy.demo.hibernate.domain.entity; import java.io.Serializable; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; // 配置表的名称 @Entity @Table(name="user") public class UserEntity implements Serializable { // MySQL 等的自增ID,用 strategy = GenerationType.IDENTITY @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(nullable = true, updatable = false) private long id; @Column(nullable = false, length = 100) private String name; // 各个getter与setter }
Repository 与 Service
Repository
java
代码解读
复制代码
package com.zxy.demo.hibernate.domain.repository; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.stereotype.Repository; import com.zxy.demo.hibernate.domain.entity.UserEntity; // 继承JpaRepository、JpaSpecificationExecutor,就有了最基本的CRUD操作,很方便是不是 @Repository public interface UserRepository extends JpaRepository<UserEntity, Long>, JpaSpecificationExecutor<UserEntity> { }
Service
java
代码解读
复制代码
package com.zxy.demo.hibernate.domain.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.zxy.demo.hibernate.domain.entity.UserEntity; import com.zxy.demo.hibernate.domain.repository.UserRepository; import com.zxy.demo.hibernate.domain.service.UserService; @Service public class UserServiceImpl implements UserService { @Autowired private UserRepository userRepository; @Override public long createUser(UserEntity userEntity) { userEntity = userRepository.saveAndFlush(userEntity); return userEntity.getId(); } @Override public void updateUser(UserEntity userEntity) { var oldUser = userRepository.findById(userEntity.getId()); if (oldUser.isEmpty()) { throw new RuntimeException("User not found. id: " + userEntity.getId()); } var oldUserEntity = oldUser.get(); oldUserEntity.setName(userEntity.getName()); // TODO 其他字段 userRepository.save(oldUserEntity); } }
api
kotlin
代码解读
复制代码
package com.zxy.demo.hibernate.api; import java.util.List; import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.zxy.demo.hibernate.domain.entity.UserEntity; import com.zxy.demo.hibernate.domain.repository.UserRepository; import com.zxy.demo.hibernate.domain.service.UserService; import com.zxy.demo.hibernate.dto.User; @Controller @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) public class UserController { // get跟list比较简单,就不封装Service接口了,直接Controller中使用 @Autowired private UserRepository userRepository; @Autowired private UserService userService; private UserEntity toUserEntity(User u) { if (null == u) { return null; } UserEntity userEntity = new UserEntity(); userEntity.setId(u.id); userEntity.setName(u.name); return userEntity; } private User toUser(UserEntity userEntity) { if (null == userEntity) { return null; } User user = new User(); user.id = userEntity.getId(); user.name = userEntity.getName(); return user; } @ResponseBody @RequestMapping(value = "/users") public List<User> users() { List<UserEntity> users = userRepository.findAll(); return users.stream().map(this::toUser).collect(Collectors.toList()); } @ResponseBody @RequestMapping(value = "/users/{id}") public User getUser(@PathVariable("id") long uid) { var user = userRepository.findById(uid); if (user.isPresent()) { return toUser(user.get()); } return null; } @ResponseBody @PostMapping(value = "/users") public User creatUser(@RequestBody User u) { UserEntity userEntity = toUserEntity(u); long id = userService.createUser(userEntity); u.id = id; return u; } @ResponseBody @PutMapping(value = "/users/{id}") public User updateUser(@PathVariable("id") long uid, @RequestBody User u) { u.id = uid; UserEntity userEntity = toUserEntity(u); userService.updateUser(userEntity); return u; } }
main
最后的main方法入口就很简单了。
java
代码解读
复制代码
@SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } }