在网站运行在apache和tomcat的负载均衡之后,总是出现一些奇怪的问题。开始有一些Duplicate entry的错误,但没在意。
今天又看了程序运行的错误信息,发现几乎都是Duplicate entry错误,集中出现在insert数据库的时候,insert user,insert message。看了Message类的主键生成是increment类型,看了看Hibernate的源代码,发现对应increment主键生成器的org.hibernate.id.IncrementGenerator 类里面,是使用select max( columnName ) from tableName的方式来获取。原来的程序一直运行很好,但是在用两个Tomcat来负载均衡后却出现问题。为什么? IncrementGenerator类里面的generate()方法虽然被声明成了synchronized,但现在两个Tomcat分别运行在两台服务器的两个独立的Java虚拟机里,显然问题在这里,synchronized只能在一个独立的Java虚拟机内部有效。所以,在两个Tomcat 中用select max同时取主键,就相当于在没有synchronized的保护下,并发时就会取出相同的值,再insert就会发生dumplicate entry的错误。
后来查看Hibernate的Reference中也提到,increment不要再集群下使用。
问题找到了,解决的办法也很简单,就是使用MySQL自己的auto_increment功能来产生主键。只需将所有Hibernate映射文件中的 increment改为native或者identity。并将数据库的主键加上auto_increment属性。
查看MySQL 5.0的文档,在14.2.6.3中介绍说:
14.2.6.3. How AUTO_INCREMENT Columns Work in InnoDB
If you specify an AUTO_INCREMENT column for an InnoDB table, the table handle in the InnoDB data dictionary contains a special counter called the auto-increment counter that is used in assigning new values for the column. This counter is stored only in main memory, not on disk.
InnoDB uses the following algorithm to initialize the auto-increment counter for a table T that contains an AUTO_INCREMENT column named ai_col: After a server startup, for the first insert into a table T, InnoDB executes the equivalent of this statement:
SELECT MAX(ai_col) FROM T FOR UPDATE;
看来在给数据库主键加上auto_increment的属性后,还要重新启动一下MySQL,这样才能保证所有的auto_increment被初始化正确。
好了,开始修改,别忘了先关掉所有的Tomcat!
问题解决后的感想:
Hibernate的主键生成虽然支持很多种数据库独有的increment方式,还有他自己的select max实现的increment方式,其实这些都不是很好,假如将来真的要切换数据库,并且是在集群下运行程序,某种数据库独有的increment和 select max方式的increment都会带来问题。
Hibernate中唯一一种最简单通用的主键生成器就是uuid。虽然是个32位难读的长字符串,但是它没有跨数据库的问题,将来切换数据库极其简单方便。推荐使用!!
分享到:
相关推荐
在Java的持久化框架Hibernate中,主键生成策略是一个至关重要的概念,它决定了数据库表中主键值如何自动生成。主键通常是表中唯一标识记录的一列,对于数据的完整性和一致性至关重要。以下是对Hibernate中主键生成...
Hibernate各种主键生成策略详解,包括 assigned increment hilo seqhilo sequence identity native uuid foreign uuid.hex sequence-identity 等
### Hibernate映射主键生成策略native #### 一、引言 在ORM(对象关系映射)技术中,Hibernate作为一款流行的Java持久层框架,在处理数据持久化方面提供了丰富的功能和灵活性。其中,主键生成策略是Hibernate配置...
### Hibernate 主键生成策略详解 #### 一、概述 Hibernate 是一款开源的对象关系映射 (ORM) 框架,它允许开发人员将 Java 对象映射到数据库表中的记录,从而极大地简化了数据访问层的开发工作。在 Hibernate 中,...
### Hibernate 主键生成策略与配置详解 #### 一、概述 在使用Hibernate进行持久化操作时,合理选择和配置主键生成策略对于确保数据的一致性和优化性能至关重要。本文将详细介绍几种常见的主键生成策略,并结合示例...
### Hibernate 主键生成策略详解 #### 一、概述 Hibernate 是一款开源的对象关系映射 (ORM) 框架,它极大地简化了 Java 应用程序与数据库之间的交互过程。在使用 Hibernate 进行持久化操作时,经常需要处理实体类...
在Java的持久化框架Hibernate中,主键生成策略是一个关键的概念,它决定了如何为数据库中的实体对象生成唯一的标识符(主键)。以下是关于Hibernate主键生成方式的详细说明: 1. **Identity方式**:`...
在Hibernate中,主键生成策略是确保实体类中的主键字段具有唯一标识的关键部分。以下是对Hibernate主键生成策略的详细说明: 1. **assigned**: 这种策略要求用户在调用`save()`方法之前手动设置主键值。Hibernate...
### Hibernate的主键生成方式详解 #### 一、概述 在使用Hibernate进行对象关系映射时,一个重要的概念就是如何为持久化实体类中的主键字段生成唯一标识符。主键是表中的一列或一组列,其值是唯一的,用于唯一地...
### hibernate主键生成策略详解 #### 一、assigned **assigned** 主键生成策略意味着主键的值是由外部程序负责生成的,并且在执行 `save()` 方法之前必须明确指定一个值。在这种策略下,Hibernate 不参与主键的...
本文将详细介绍Hibernate提供的几种常见的主键生成策略,包括assigned、increment、identity以及native等,并探讨它们各自的适用场景及优缺点。 #### 二、主键概述 主键可以分为两种类型:自然主键和代理主键。 1....
本篇文章将详细讲解Hibernate映射文件中关于主键生成的各种策略及其配置,帮助开发者更好地理解和使用。 首先,主键(Primary Key)是数据库表中用于唯一标识一条记录的字段,其值在表中必须是唯一的,并且通常不...
本文将详细介绍Hibernate中五种常用的主键生成策略:assigned、increment、hilo、seqhilo以及native,并探讨它们的特点、应用场景及配置方式。 #### 二、assigned **定义与用途:** - **定义:**assigned策略允许...
### Hibernate 主键生成策略详解 Hibernate 是一款流行的 Java 持久层框架,它提供了对象关系映射(ORM)的功能,使得 Java 开发者能够更高效地与数据库进行交互。在 Hibernate 中,主键生成策略是一项核心功能,...