Hibernate + MySQL:如何为数据库和表设置utf-8编码?

27

我使用的操作系统是Linux Mandriva,关系型数据库管理系统是MySQL 5

我需要在UTF-8编码下创建数据库和表格。

以下是hibernate.cfg.xml的一部分内容 -

... 
 <property name="hibernate.hbm2ddl.auto">create-drop</property>   
 <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
 <property name="hibernate.connection.characterEncoding">utf8</property> 
...

my.cnf -

# The MySQL server
[mysqld]
...
default-character-set=cp1251
character-set-server=cp1251
collation-server=cp1251_general_ci
init-connect="SET NAMES cp1251"
skip-character-set-client-handshake
...
[mysqldump]
...    
default-character-set=cp1251
...

例如,某些类:

@Entity
@Table(name = "USER")
public class User {
    @Id 
    @Column(name = "USERID")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    @Column(name = "USERNAME")
    private String name;

    @Column(name = "USERPASSWORD")
    private String password;

    @Column(name = "USERIP")
    private String ip;
        // getter's and setter's here
        ...

但是当表格被生成时,我看到编码为 latin1 例如-

SHOW CREATE TABLE USER;

USER  | CREATE TABLE `user` (
  `USERID` int(11) NOT NULL auto_increment,
  `USERIP` varchar(255) default NULL,
  `USERNAME` varchar(255) default NULL,
  `USERPASSWORD` varchar(255) default NULL,
  PRIMARY KEY  (`USERID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |

如何将编码更改为UTF-8?
非常感谢提供信息!谢谢!
...
这很奇怪,我已经全部更改为utf8 -
# The MySQL server
    [mysqld]
    ...
    default-character-set=utf8
    character-set-server=utf8
    collation-server=utf8_general_ci
    init-connect="SET NAMES utf8"
    skip-character-set-client-handshake
    ...
    [mysqldump]
    ...    
    default-character-set=utf8
    ...

现在 -

SHOW CREATE TABLE USER;

USER  | CREATE TABLE `USER` (
  `USERID` int(11) NOT NULL auto_increment,
  `USERIP` varchar(255) default NULL,
  `USERNAME` varchar(255) default NULL,
  `USERPASSWORD` varchar(255) default NULL,
  PRIMARY KEY  (`USERID`)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251 |

my.cnf: default-character-set=cp1251?将其更改为utf8! - rkosegi
1
这对我很有用,可以找出在应用各种默认值后我最终使用的字符集和排序规则。SELECT CHARACTER_SET_NAME, COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='<database-name>' AND TABLE_NAME='<table-name>' AND COLUMN_NAME='<column-name>'; - Emanuel George Hategan
9个回答

59

您还可以使用编码创建数据库。
只需使用phpMyAdmin创建数据库/表。

在Hibernate设置的URL中指定一些URL参数,以便连接使用UTF8:

<!-- Database Settings -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<!--  for performance reasons changed to MyISAM from org.hibernate.dialect.MySQLInnoDBDialect -->
<property name="dialect">org.openmeetings.app.hibernate.utils.MySQL5MyISAMDialect</property>
<property name="connection.url">jdbc:mysql://localhost/openmeetings?autoReconnect=true&amp;useUnicode=true&amp;createDatabaseIfNotExist=true&amp;characterEncoding=utf-8</property>    

<property name="hibernate.connection.CharSet">utf8</property>
<property name="hibernate.connection.characterEncoding">utf8</property>
<property name="hibernate.connection.useUnicode">true</property>

你不需要将数据库的整个编码设置为utf8。 只有在使用UTF-8字符集的时候才需要这样做。

<!-- Database Scheme Auto Update -->
<property name="hbm2ddl.auto">update</property>   

您需要将MySQL的默认编码设置为utf8,因为hbm2dll将使用数据库的默认编码。

如果您仍然使用hbm2ddl.auto,并手动修改数据库表以具有utf8校对规则。

如果您不使用hbm2ddl.auto,可以使用您喜欢的编码简单地创建表格。无需设置数据库为特殊编码。

Sebastian


1
我应该额外注意到,我在URL参数中使用了createDatabaseIfNotExist=true,这意味着数据库将以默认编码创建。这就是为什么你需要在my.cnf中设置系统范围的编码。 - seba.wagner
值得注意的是,在生产环境中不建议使用"hbm2ddl.auto"的"update"选项。请参考https://dev59.com/fHVC5IYBdhLWcg3wpjB8。 - MPV
如何处理 postgreSQL 数据库? - prem30488
我曾经遇到过同样的问题,但是Hibernate属性并没有帮助我解决问题,因为我使用了不同的连接池来创建我的数据库连接。在我的情况下,我使用的是tomcat.jdbc连接池,所以编码必须在org.apache.tomcat.jdbc.pool.DataSource的PoolProperties中设置。 - ibai

18

如何将编码更改为UTF-8?

我使用了一个本地方言类,扩展了MySQLDialect并更改了表类型字符串:

public class LocalMysqlDialect extends MySQLDialect {
    @Override
    public String getTableTypeString() {
        return " DEFAULT CHARSET=utf8";
    }
}

我实际上是在扩展MySQL5InnoDBDialect类型,所以我真正使用的是:

public class LocalMysqlDialect extends MySQL5InnoDBDialect {
    @Override
    public String getTableTypeString() {
        return " ENGINE=InnoDB DEFAULT CHARSET=utf8";
    }
}

hibernate.connection.CharSethibernate.connection.characterEncodinghibernate.connection.useUnicode属性似乎在我的环境中不起作用(我使用的是Spring Boot 1.3.3),但继承MySQL5InnoDBDialect终于解决了问题。 - Paraita

15

考虑像这样更改连接URL配置:

<property name="hibernate.connection.url">
    jdbc:mysql://localhost/yourdatabase?UseUnicode=true&amp;characterEncoding=utf8
</property>

它解决了这个案件。


1
救了我的一天!谢谢! - Jagger
1
我使用Spring Boot,但是你的解决方案对我很有帮助,谢谢。我在application.properties文件中的sprind.datasource.url=jdbc:mysql://localhost:3306/mydatabase?useUnicode=true&characterEncoding=utf8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC行中添加了characterEncoding=utf8参数。 - Yamashiro Rion

6
首先,在Java方面,您应该指定UTF-8而不是utf8,请参考此处的表格
其次,characterEncoding并不是您的表将创建的字符集,这只是在与数据库通信和读取/写入数据时使用的字符集。 MySQL 文档说明,在创建表时,如果没有指定,则将使用 DB 字符集。这意味着为了实现这一点,您的数据库(不是 MySQL 服务器)应该这样创建: create database DB_NAME character set utf8; 之后,在此数据库中创建的表应该使用 utf8 编码。排序规则也是如此。
但是,当然不能依赖 Hibernate 的 hbm2ddl,请阅读这里了解更多细节。

5
我是使用Spring-Data的。我尝试在URL中激活参数:
jdbc:mysql://localhost:3306/DATABASE?createDatabaseIfNotExist=true&amp;useUnicode=true&amp;characterEncoding=utf-8

此外,我已经尝试了使用Hibernate属性的方法,但对我最终起作用的解决方案是@Gray提出的那个。
@Bean
@Autowired
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    vendorAdapter.setGenerateDdl(dbGenerateDdl); 
    vendorAdapter.setShowSql(dbShowSql);
    if (Arrays.asList(environment.getActiveProfiles()).contains("prod"))
        vendorAdapter.setDatabasePlatform(CustomMysqlDialect.class.getName());

    Properties jpaProperties = new Properties();
    jpaProperties.put("hibernate.connection.CharSet", "utf-8");
    jpaProperties.put("hibernate.connection.useUnicode", true);
    jpaProperties.put("hibernate.connection.characterEncoding", "utf-8");

    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    factory.setJpaVendorAdapter(vendorAdapter);
    factory.setPackagesToScan("com.example.model");
    factory.setDataSource(dataSource);
    factory.setJpaProperties(jpaProperties);

    return factory;
}

这行代码救了我的一天:
vendorAdapter.setDatabasePlatform(CustomMysqlDialect.class.getName());

4

对于使用Spring Boot的用户:请在您的application.properties文件中,将characterEncoding=utf8参数添加到此行:

spring.datasource.url=jdbc:mysql://localhost:3306/mydatabase?useUnicode=true&characterEncoding=utf8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC

1
通过Spring Java配置的dataSource()方法,这应该会有所帮助:
@Bean
public DataSource dataSource() {    
    BasicDataSource dataSource = new BasicDataSource();    
    //your username/pass props
    dataSource.setConnectionProperties("useUnicode=true;characterEncoding=utf8;characterSetResults=UTF-8;");
    return dataSource;
}

在属性字符串的末尾要小心使用';'!


1

如何更改数据库排序规则?

ALTER DATABASE [database] CHARACTER SET utf8 COLLATE utf8_unicode_ci;


1
你可以使用Hibernate的@Type属性,根据你的要求自定义注解并应用于字段顶部。例如:
  public class PhoneNumberType implements UserType {
    @Override
    public int[] sqlTypes() {
  return new int[]{Types.INTEGER, Types.INTEGER, Types.INTEGER};
    }

    @Override
    public Class returnedClass() {
        return PhoneNumber.class;
    }

    // other methods
    }   

首先,是 null SafeGet 方法:
    @Override
    public Object nullSafeGet(ResultSet rs, String[] names, 
    SharedSessionContractImplementor session, Object owner) throws HibernateException,                   
      SQLException {
    int countryCode = rs.getInt(names[0]);
     if (rs.wasNull())
        return null;
     int cityCode = rs.getInt(names[1]);
    int number = rs.getInt(names[2]);
    PhoneNumber employeeNumber = new PhoneNumber(countryCode, cityCode, number);
     return employeeNumber;
     }

下面是 null 安全的 Set 方法:

    @Override
     public void nullSafeSet(PreparedStatement st, Object value, 
      int index, SharedSessionContractImplementor session) 
       throws HibernateException, SQLException {
        if (Objects.isNull(value)) {
        st.setNull(index, Types.INTEGER);
        } else {
        PhoneNumber employeeNumber = (PhoneNumber) value;
        st.setInt(index,employeeNumber.getCountryCode());
        st.setInt(index+1,employeeNumber.getCityCode());
        st.setInt(index+2,employeeNumber.getNumber());
      }
     }

最后,在我们的OfficeEmployee实体类中,我们可以声明自定义的PhoneNumberType:

    @Entity
    @Table(name = "OfficeEmployee")
     public class OfficeEmployee {

      @Columns(columns = { @Column(name = "country_code"), 
      @Column(name = "city_code"), @Column(name = "number") })
      @Type(type = "com.baeldung.hibernate.customtypes.PhoneNumberType")
       private PhoneNumber employeeNumber;

     // other fields and methods
      }

这可能解决您的问题,适用于所有数据库。如果您需要更多信息,请参考:: https://www.baeldung.com/hibernate-custom-types 同样,您还需要进行UTF-8编码/解码和ISO-8859-1解码/编码。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接