JDBC 4 增加了显式处理 nationalized character data 的能力,为此 java.sql.Types 增加了
- NCHAR
 - NVARCHAR
 - LONGNVARCHAR
 - NCLOB
 
Hibernate 使用 @Nationalized map a specific attribute to a nationalized variant data type
NVARCHAR
package org.example.demo.hibernate;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Persistence;
import org.hibernate.annotations.Nationalized;
public class Test {
    public static void main(String[] args) throws Exception {
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
        EntityManager em = factory.createEntityManager();
        Product product = new Product();
        product.warranty = "test";
        em.getTransaction().begin();
        em.persist(product);
        em.getTransaction().commit();
        em.clear();
        Product p = em.find(Product.class, product.id);
        // test
        System.out.println(p.warranty);
        em.close();
        factory.close();
    }
    @Entity(name = "Product")
    public static class Product {
        @Id
        @GeneratedValue
        Integer id;
        @Nationalized
        String warranty;
    }
}
生成的 SQL
drop table if exists Product cascade
drop sequence if exists hibernate_sequence
create sequence hibernate_sequence start 1 increment 1
create table Product (id int4 not null, warranty varchar(255), primary key (id))
select nextval ('hibernate_sequence')
insert into Product (warranty, id) values ('test', 1)
select test_produ0_.id as id1_0_0_, test_produ0_.warranty as warranty2_0_0_ from Product test_produ0_ where test_produ0_.id=1
NCLOB
package org.example.demo.hibernate;
import java.io.BufferedReader;
import java.io.Reader;
import java.sql.NClob;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Persistence;
import org.hibernate.annotations.Nationalized;
import org.hibernate.engine.jdbc.NClobProxy;
public class Test {
    public static void main(String[] args) throws Exception {
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
        EntityManager em = factory.createEntityManager();
        Product product = new Product();
        product.warranty = NClobProxy.generateProxy("test");
        em.getTransaction().begin();
        em.persist(product);
        em.getTransaction().commit();
        em.clear();
        em.getTransaction().begin();
        Product p = em.find(Product.class, product.id);
        try (Reader reader = p.warranty.getCharacterStream()) {
            BufferedReader in = new BufferedReader(reader);
            String line;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
        }
        em.getTransaction().commit();
        em.close();
        factory.close();
    }
    @Entity(name = "Product")
    public static class Product {
        @Id
        @GeneratedValue
        Integer id;
        @Lob
        @Nationalized
        NClob warranty;
    }
}
在 postgres 下运行第 28 行抛异常 java.sql.SQLFeatureNotSupportedException: 这个 org.postgresql.jdbc.PgPreparedStatement.setNClob(int, NClob) 方法尚未被实作。
使用 materialized form
package org.example.demo.hibernate;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Persistence;
import org.hibernate.annotations.Nationalized;
public class Test {
    public static void main(String[] args) throws Exception {
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
        EntityManager em = factory.createEntityManager();
        Product product = new Product();
        product.warranty = "test";
        em.getTransaction().begin();
        em.persist(product);
        em.getTransaction().commit();
        em.clear();
        Product p = em.find(Product.class, product.id);
        // test
        System.out.println(p.warranty);
        em.close();
        factory.close();
    }
    @Entity(name = "Product")
    public static class Product {
        @Id
        @GeneratedValue
        Integer id;
        @Lob
        @Nationalized
        String warranty;
    }
}
生成 SQL
drop table if exists Product cascade
drop sequence if exists hibernate_sequence
create sequence hibernate_sequence start 1 increment 1
create table Product (id int4 not null, warranty text, primary key (id))
select nextval ('hibernate_sequence')
insert into Product (warranty, id) values ('test', 1)
select test_produ0_.id as id1_0_0_, test_produ0_.warranty as warranty2_0_0_ from Product test_produ0_ where test_produ0_.id=1
package org.example.demo.hibernate;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Persistence;
import org.hibernate.annotations.Nationalized;
public class Test {
    public static void main(String[] args) throws Exception {
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
        EntityManager em = factory.createEntityManager();
        Product product = new Product();
        product.warranty = "test".toCharArray();
        em.getTransaction().begin();
        em.persist(product);
        em.getTransaction().commit();
        em.clear();
        Product p = em.find(Product.class, product.id);
        // test
        System.out.println(p.warranty);
        em.close();
        factory.close();
    }
    @Entity(name = "Product")
    public static class Product {
        @Id
        @GeneratedValue
        Integer id;
        @Lob
        @Nationalized
        char[] warranty;
    }
}
生成 SQL
drop table if exists Product cascade
drop sequence if exists hibernate_sequence
create sequence hibernate_sequence start 1 increment 1
create table Product (id int4 not null, warranty text, primary key (id))
select nextval ('hibernate_sequence')
insert into Product (warranty, id) values ('test', 1)
select test_produ0_.id as id1_0_0_, test_produ0_.warranty as warranty2_0_0_ from Product test_produ0_ where test_produ0_.id=1
如果 application and database 都是完全 nationalized ,则可以设置 hibernate.use_nationalized_character_data 或者 MetadataBuilder#enableGlobalNationalizedCharacterDataSupport() 以默认启用 nationalized character data 。