[ ] 中文文档
hibernate
-
public static void main(String[] args) {//创建对象User user = new User();user.setPassword("123");user.setCellphone("122222");user.setUsername("nihao");//获取加载配置管理类Configuration configuration = new Configuration();//不给参数就默认加载hibernate.cfg.xml文件,configuration.configure();//创建Session工厂对象SessionFactory factory = configuration.buildSessionFactory();//得到Session对象Session session = factory.openSession();//使用Hibernate操作数据库,都要开启事务,得到事务对象Transaction transaction = session.getTransaction();//开启事务transaction.begin();//把对象添加到数据库中session.save(user);//提交事务transaction.commit();//关闭Sessionsession.close();}
- orm配置:xml或注解方式
- 数据库连接配置:一个
session-factory代表一个数据库 - SessionFactory和Session
Session是Hibernate最重要的对象,Session维护了一个连接(Connection),只要使用Hibernate操作数据库,都需要用到Session对象。
- 开启事务
SimpleHibernateDao
// 封装示例代码片段:public class SimpleHibernateDao<T, PK extends Serializable> {// ...protected SessionFactory sessionFactory;protected Class<T> entityClass;@Autowiredpublic void setSessionFactory(SessionFactory sessionFactory) {this.sessionFactory = sessionFactory;}public Session getSession() {return this.sessionFactory.getCurrentSession();}public void save(T entity) {Assert.notNull(entity, "entity不能为空");this.getSession().saveOrUpdate(entity);this.logger.debug("save entity: {}", entity);}// ...}
hibernate-entitymanager
<?xml version="1.0" encoding="UTF-8"?><persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0"><!-- 持久化单元--><!-- JTA: 分布式事务管理--><!-- RESOURCE_LOCAL: 本地事务管理--><persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL"><!-- jpa的实现方式--><provider>org.hibernate.jpa.HibernatePersistenceProvider</provider><!-- 数据库信息--><properties><property name="javax.persistence.jdbc.user" value="root"/><property name="javax.persistence.jdbc.password" value="root"/><property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/><property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpa?allowPublicKeyRetrieval=true%26useSSL=false%26serverTimezone=UTC"/><!-- 可选配置:配置jpa实现方的配置信息--><!-- 显示sql,打印在控制台--><property name="hibernate.show_sql" value="true"/><!-- 自动创建数据库表--><!-- create: 程序运行时创建数据库表,如果有表,先删除再创建--><!-- update: 程序运行时创建表,如果有表,不会创建表--><!-- none: 不创建表--><property name="hibernate.hbm2ddl.auto" value="create"/></properties></persistence-unit></persistence>
public class JpaTest {@Testpublic void testSave() {// 1. 加载配置文件创建工厂(实体管理类工厂)对象EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");// 2. 通过实体管理类工厂获取实体管理器EntityManager entityManager = factory.createEntityManager();// 3. 获取事务对象,开启事务EntityTransaction tx = entityManager.getTransaction();tx.begin();// 4. 完成增删改查操作Customer customer = new Customer();customer.setCustName("Thiago");customer.setCustIndustry("sports");entityManager.persist(customer); // 保存操作// 5. 提交事务(回滚事务)tx.commit();// 6. 释放资源entityManager.close();factory.close();}}
缓存
持久化状态
- 修改持久化对象属性,会修改数据库的值。
下面的sql应该只是生成sql语句,真正执行应该是事务结束commit时执行。
//把数据放进cacheUser user = (User) session.get(User.class, 1);//发现要修改的字段和cache一样,不执行user.setUserName("你好2");
- 和cache的数据一样,不会执行更新。

- 查询也是,对应的SQL
User user = null;user = (User) session.get(User.class, 1);user = (User) session.get(User.class, 1);
JPA中的快照机制(缓存同步)
如上图,JPA 向一级缓存放入数据时,同时复制一份数据放入快照中,当使用commit()方法提交事务时,同时会清理一级缓存,这时会使用主键字段的值判断一级缓存中的对象和快照中的对象是否一致,如果两个对象中的属性发生变化,则执行update语句,将缓存的内容同步到数据库,并更新快照;如果一致,则不执行update语句。
快照的作用就是确保一级缓存中的数据和数据库中的数据一致。
懒加载和Entity Graph
Entity Graph的使用
JPA Entity Graph — Baeldung
Spring Data JPA and Named Entity Graphs
- With @NamedEntityGraph
- ad-hoc entity graph
[JavaEE - JPA] 性能优化: 4种触发懒加载的方式
- 通过方法调用触发
- 通过Join Fetch触发
- 通过NamedEntityGraph触发
- 通过动态的EntityGraph触发
What’s the difference between fetchgraph and loadgraph in JPA 2.1?
When using fetchgraph all relationships are considered to be lazy regardless of annotation, and only the elements of the provided graph are loaded. This particularly useful when running reports on certain objects and you don’t want a lot of the stuff that’s normally flagged to load via eager annotations. 只有entityGraph中的属性被加载 If you want to eagerly load entities that are normally loaded via lazy annotation, you may use loadgraph to add entities to the query results that would normally be loaded later, thereby avoiding specific N+1 cases. Relationships that were already flagged as eager will continue to be loaded as usual. 除了entityGraph中的属性,还有fetch type为eager的也会被加载
可以在运行期决定是否即时加载关联字段,通过在find方法内传入参数,结合”javax.persistence.fetchgraph”, “”javax.persistence.loadgraph””,解决静态扩展问题和查询N+1性能问题。
- The main goal of the JPA Entity Graph is then to improve the runtime performance when loading the entity’s related associations and basic fields.
- Briefly put, the JPA provider loads all the graph in one select query and then avoids fetching association with more SELECT queries. This is considered a good approach for improving application performance.
FecthType事务的坑
FetchType.LAZY: The persistence provider should load data when it’s first accessed, but can be loaded eagerly. This is the default behavior for @OneToMany, @ManyToMany and @ElementCollection-annotated fields.
Hibernate: failed to lazily initialize a collection of role, no session or session was closed
failed to lazily initialize a collection of role,..could not initialize proxy - no Session - JPA + SPRING
注意:@oneToMany使用FetchType-Lazy的话,需要在事务之内。用到了事务传播行为。
linkmans使用Lazy load,通过customer.getLinkmans()访问的时候才真正从数据库获取,这时候已经不在JpaRepository的事务中了,所以要在外层包裹事务,把JPA的事务合并到外层事务中。
public class CustomerDaoTest {@Test@Transactional@Rollback(false)public void testFindById() {Customer customer = customerDao.findById(1L).get();log.info("linkman size is: " + customer.getLinkmans().size());}}public class Customer implements Serializable {// ……@OneToMany(mappedBy = "customer",fetch = FetchType.LAZY,cascade = CascadeType.ALL)@ToString.Excludeprivate Set<LinkMan> linkmans = new HashSet<>();}

