dfb*_*dfb 13 java sql-server hibernate jdbc
我目前正在大型数据库的某些表中启用UTF-8字符.这些表已经是MS-SQL类型的NVARCHAR.另外,我还有几个使用VARCHAR的字段.
Hibernate与JDBC驱动程序的交互存在一个众所周知的问题(参见例如,在hibernate中映射到varchar和nvarchar).简而言之,Hibernate/JDBC生成的SQL将所有字符串作为Unicode传递,而不管底层的SQL类型如何.当数据库中的非unicode(varchar)字段与Unicode输入字符串进行比较时,该列的指示与编码不匹配,因此执行全表扫描.在JDBC驱动程序(JTDS和MS版本)中,有一个参数可以将Unicode字符串作为ASCII传递,但这是一个全有或全无的命题,它不允许将国际字符输入到数据库中.
我在这个问题上看到的大多数帖子都提出了两个解决方案中的一个 - 1)将数据库中的所有内容更改为NVARCHAR或2)设置sendStringParametersAsUnicode = false,我的问题是这个 - 是否有任何已知的解决方案来使用VARCHAR和NVARCHAR一起玩得很好?由于下游依赖性和其他外部问题,我的环境将一切都更改为NVARCHAR 是一个巨大的问题.
小智 5
公共类 SQLServerUnicodeDialect 扩展 org.hibernate.dialect.SQLServerDialect {
公共 SQLServerUnicodeDialect() {
极好的();
registerColumnType(Types.CHAR, "nchar(1)");
registerColumnType(Types.LONGVARCHAR, "nvarchar(max)");
registerColumnType(Types.VARCHAR, 4000, "nvarchar($l)");
registerColumnType(Types.VARCHAR, "nvarchar(max)");
registerColumnType(Types.CLOB, "nvarchar(max)" );
registerColumnType(Types.NCHAR, "nchar(1)");
registerColumnType(Types.LONGNVARCHAR, "nvarchar(max)");
registerColumnType(Types.NVARCHAR, 4000, "nvarchar($l)");
registerColumnType(Types.NVARCHAR, "nvarchar(max)");
registerColumnType(Types.NCLOB, "nvarchar(max)");
registerHibernateType(Types.NCHAR, StandardBasicTypes.CHARACTER.getName());
registerHibernateType(Types.LONGNVARCHAR, StandardBasicTypes.TEXT.getName());
registerHibernateType(Types.NVARCHAR, StandardBasicTypes.STRING.getName());
registerHibernateType(Types.NCLOB, StandardBasicTypes.CLOB.getName());
}
}
我决定尝试将此作为一种无需接触数据库即可工作的 hack。为此,我为 NVARCHAR 字段创建了一个自定义类型。这需要 JDBC 4 驱动程序(使用 Microsoft 的驱动程序)和 Hibernate 3.6.0。sendStringParametersAsUnicode 为 false。
这是方法,我仍在验证其正确性 - 欢迎比我更有经验的人发表评论
添加新的方言以支持新的数据类型
public class SQLAddNVarCharDialect extends SQLServerDialect {
public SQLAddNVarCharDialect(){
super();
registerColumnType( Types.NVARCHAR, 8000, "nvarchar($1)" );
registerColumnType( Types.NVARCHAR, "nvarchar(255)" );
}
}
Run Code Online (Sandbox Code Playgroud)
添加新类型。注意setNString在nullSafeSet
public class NStringUserType implements UserType {
@Override
public Object assemble(Serializable arg0, Object owner)
throws HibernateException {
return deepCopy(arg0);
}
@Override
public Object deepCopy(Object arg0) throws HibernateException {
if(arg0==null) return null;
return arg0.toString();
}
@Override
public Serializable disassemble(Object arg0) throws HibernateException {
return (Serializable)deepCopy(arg0);
}
@Override
public boolean equals(Object arg0, Object arg1) throws HibernateException {
if(arg0 == null )
return arg1 == null;
return arg0.equals(arg1);
}
@Override
public int hashCode(Object arg0) throws HibernateException {
return arg0.hashCode();
}
@Override
public boolean isMutable() {
return false;
}
@Override
public void nullSafeSet(PreparedStatement st, Object value, int index)
throws HibernateException, SQLException {
if(value == null)
st.setNull(index,Types.NVARCHAR);
else
st.setNString(index, value.toString());
}
@Override
public Object replace(Object arg0, Object target, Object owner)
throws HibernateException {
return deepCopy(arg0);
}
@Override
public Class returnedClass() {
return String.class;
}
@Override
public int[] sqlTypes() {
return new int[]{Types.NVARCHAR};
}
@Override
public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner)
throws HibernateException, SQLException {
String result = resultSet.getString(names[0]);
return result == null || result.trim().length() == 0
? null : result;
}
}
Run Code Online (Sandbox Code Playgroud)
更新所有 NVARCHAR 字段的映射
<property name="firstName" type="NStringUserType">
<column name="firstName" length="40" not-null="false" />
</property>
Run Code Online (Sandbox Code Playgroud)
之前的原始 SQL(使用 sendUnicode..=true):
exec sp_prepexec @p1 output,N'@P0 nvarchar(4000),@P1 datetime,@P2 varchar(8000),@P3 nvarchar(4000),@P4 nvarchar(4000),@P5 nvarchar(4000),@P6 nvarchar(4000)... ,N'update Account set ... where AccountId=@P35
Run Code Online (Sandbox Code Playgroud)
之后:
exec sp_prepexec @p1 output,N'@P0 varchar(8000),@P1 .... @P6 nvarchar(4000),@P7 ... ,N'update Account set ... Validated=@P4, prefix=@P5, firstName=@P6 ... where AccountId=@P35
Run Code Online (Sandbox Code Playgroud)
似乎对于“选择..”的工作原理类似
| 归档时间: |
|
| 查看次数: |
20658 次 |
| 最近记录: |