使用shardingsphere对SQLServer坑的解决
背景:最近一个使用SQLServer的项目,业务量太大,开始对业务有影响了,因此用户要求升级改造,技术上采用shardingsphere进行分库分表。
经过一系列调研,设计。。。哐哐一顿操作之后开始动刀改造。pom依赖如下:
<!--sharding--> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>4.0.1</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.8</version> </dependency>
改造后查询和写入都各种报错:
Caused by: org.apache.ibatis.type.TypeException: Error setting non null for parameter #2 with JdbcType NVARCHAR . Try setting a different JdbcType for this parameter or a different configuration property. Cause: java.sql.SQLFeatureNotSupportedException: setNString
at org.apache.ibatis.type.BaseTypeHandler.setParameter(BaseTypeHandler.java:75)
at org.apache.ibatis.scripting.defaults.DefaultParameterHandler.setParameters(DefaultParameterHandler.java:87)
... 47 common frames omitted
Caused by: java.sql.SQLFeatureNotSupportedException: setNString
at org.apache.shardingsphere.shardingjdbc.jdbc.unsupported.AbstractUnsupportedOperationPreparedStatement.setNString(AbstractUnsupportedOperationPreparedStatement.java:57)
at org.apache.ibatis.type.NStringTypeHandler.setNonNullParameter(NStringTypeHandler.java:31)
at org.apache.ibatis.type.NStringTypeHandler.setNonNullParameter(NStringTypeHandler.java:26)
at org.apache.ibatis.type.BaseTypeHandler.setParameter(BaseTypeHandler.java:73)
... 48 common frames omitted
核心错误:Caused by: java.sql.SQLFeatureNotSupportedException: setNString
问题分析:
网上寻了千百度,蓦然回首,还是没有找到问题,(┭┮﹏┭┮) 最后debug断点跟了源码发现:
操作数据库的PreparedStatement 是ShardingPreparedStatement
然后setNString支持SQLServerPreparedStatement 不支持ShardingPreparedStatement(改造前没问题,改造后出问题的原因)
问题解决:
找到问题了,下面就是解决问题了,既然没有setNString的实现,那就实现一个呗;
第一步 实现NVarcharTypeHandler:
package cn.preserve.config.mybatis; import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.MappedJdbcTypes; import org.apache.ibatis.type.TypeException; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; /** * 将 nvarchar 转成 varchar sharingJDBC不支持nvarchar * 主要是NStringTypeHandler中,没有setNString() */ @MappedJdbcTypes(JdbcType.NVARCHAR) public class NVarcharTypeHandler extends BaseTypeHandler<String> { @Override public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { if(parameter == null) { if(jdbcType == null) { throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters."); } try { ps.setNull(i, jdbcType.TYPE_CODE); } catch (SQLException var7) { throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " + "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " + "Cause: " + var7, var7); } } else { try { this.setNonNullParameter(ps, i, parameter, jdbcType); } catch (Exception var6) { throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . " + "Try setting a different JdbcType for this parameter or a different configuration property. " + "Cause: " + var6, var6); } } } /** * 这里使用setNString而不是setString * @param ps * @param i * @param parameter * @param jdbcType * @throws SQLException */ @Override public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, parameter); } @Override public String getNullableResult(ResultSet rs, String columnName) throws SQLException { return rs.getString(columnName); } @Override public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return rs.getString(columnIndex); } @Override public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return cs.getString(columnIndex); } }
第二步 实现加入数据库配置:
由于我是代理实现的数据库,所有在代码中加入即可
@Configuration public class DataSourceConfig { @Bean(name = "sqlSessionFactory") @Primary public SqlSessionFactory memberDb1SqlSessionFactory(DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = getSqlSessionFactoryBean(dataSource); bean.setTypeHandlers(new TypeHandler[] {new NVarcharTypeHandler()}); return bean.getObject(); } // ******* 其他实现 }
PS:如果是配置只修要在mybatis-config.xml中配置一下
<typeHandlers> <typeHandler handler="cn.preserve.config.mybatis.NVarcharTypeHandler"/> </typeHandlers>
配置完成后,测试以前功能全部正常(#^.^#)
如果嫌麻烦,有另外一种解决方案:将mapper.xml中的NVARCHAR替换从VARCHAR也可以哦
到此这篇关于使用shardingsphere对SQLServer坑的解决的文章就介绍到这了,更多相关shardingsphere SQLServer内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!