使用shardingsphere 尝试进行分库时,报错 Missing the data source name: ‘null’
详细错误内容
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
### Error updating database. Cause: java.lang.IllegalStateException: Missing the data source name: 'null'
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: INSERT INTO user (user_id, user_name) VALUES (?, ?)
### Cause: java.lang.IllegalStateException: Missing the data source name: 'null'
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:79)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:447)
at com.sun.proxy.$Proxy60.insert(Unknown Source)
at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:279)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:57)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59)
at com.sun.proxy.$Proxy65.addEntity(Unknown Source)
at com.tianyilan.shardingsphere.demo.service.impl.UserServiceImpl.insertUsers(UserServiceImpl.java:57)
at com.tianyilan.shardingsphere.demo.service.impl.UserServiceImpl.processUsers(UserServiceImpl.java:31)
at com.tianyilan.shardingsphere.demo.UserServiceTest.testProcessUsers(UserServiceTest.java:21)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)
Caused by: org.apache.ibatis.exceptions.PersistenceException:
### Error updating database. Cause: java.lang.IllegalStateException: Missing the data source name: 'null'
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: INSERT INTO user (user_id, user_name) VALUES (?, ?)
### Cause: java.lang.IllegalStateException: Missing the data source name: 'null'
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:200)
at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:185)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:434)
... 38 more
Caused by: java.lang.IllegalStateException: Missing the data source name: 'null'
at com.google.common.base.Preconditions.checkState(Preconditions.java:197)
at org.apache.shardingsphere.shardingjdbc.jdbc.adapter.AbstractConnectionAdapter.getConnections(AbstractConnectionAdapter.java:110)
at org.apache.shardingsphere.shardingjdbc.executor.PreparedStatementExecutor$1.getConnections(PreparedStatementExecutor.java:79)
at org.apache.shardingsphere.core.execute.sql.prepare.SQLExecutePrepareTemplate.getSQLExecuteGroups(SQLExecutePrepareTemplate.java:89)
at org.apache.shardingsphere.core.execute.sql.prepare.SQLExecutePrepareTemplate.getSynchronizedExecuteUnitGroups(SQLExecutePrepareTemplate.java:67)
at org.apache.shardingsphere.core.execute.sql.prepare.SQLExecutePrepareTemplate.getExecuteUnitGroups(SQLExecutePrepareTemplate.java:59)
at org.apache.shardingsphere.shardingjdbc.executor.PreparedStatementExecutor.obtainExecuteGroups(PreparedStatementExecutor.java:75)
at org.apache.shardingsphere.shardingjdbc.executor.PreparedStatementExecutor.init(PreparedStatementExecutor.java:70)
at org.apache.shardingsphere.shardingjdbc.jdbc.core.statement.ShardingPreparedStatement.initPreparedStatementExecutor(ShardingPreparedStatement.java:198)
at org.apache.shardingsphere.shardingjdbc.jdbc.core.statement.ShardingPreparedStatement.execute(ShardingPreparedStatement.java:171)
at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:46)
at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:74)
at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:50)
at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117)
at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76)
at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:198)
... 44 more
你所插入的表 没有配置相关的路由信息。例如我的properties内容如下
spring.shardingsphere.datasource.names=ds0,ds1
spring.shardingsphere.datasource.ds0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds0.url = jdbc:mysql://localhost:3306/shardingsphere_1
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=123
spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds1.url = jdbc:mysql://localhost:3306/shardingsphere_2
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=123
spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column= user_id
spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression= ds$->{user_id %2}
spring.shardingsphere.sharding.binding-tables=health_record,health_task
spring.shardingsphere.sharding.broadcast-tables=health_level
#spring.shardingsphere.sharding.tables.user.actual-data-nodes=ds$->{0..1}.user
spring.shardingsphere.sharding.tables.health_record.actual-data-nodes=ds$->{0..1}.health_record
spring.shardingsphere.sharding.tables.health_record.key-generator.column=record_id
spring.shardingsphere.sharding.tables.health_record.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.health_record.key-generator.props.worker.id=33
spring.shardingsphere.sharding.tables.health_task.actual-data-nodes=ds$->{0..1}.health_task
spring.shardingsphere.sharding.tables.health_task.key-generator.column=task_id
spring.shardingsphere.sharding.tables.health_task.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.health_task.key-generator.props.worker.id=33
#logging.level.com.tianyilan.shardingsphere.demo.entity=debug
spring.shardingsphere.props.sql.show=true
我配置了 health_record,health_task 的路由规则,但是我测试数据插入的表是 user表。由于没有配置,所以定位不了数据库。如果更改一下,变成
那么就可以了
首先,最终抛出异常的地方 SQLExecutePrepareTemplate
类
划红线的地方执行出错,进去看一下内容
划红线的地方出错,因为dataSourceName 是null。
而这个入参是在PreparedStatementExecutor中传入的(下面的routeUnits)
它是被同类下的(init 方法所调用)
它是被ShardingPreparedStatement 的 (initPreparedStatementExecutor 方法调用)
它是被同类下的 (execute 方法调用)
定位可知,值是从该类的私有变量 routeResult 中获得的,而它是在shard() 方法中赋值的。
这里调用的是BaseShardingEngine
进入route方法
BaseShardingEngine 抽象类的抽象方法
进入它的实现类 PreparedQueryShardingEngine
进入到route,跳转到 PreparedStatementRoutingEngine 类
进入到内层route方法 中 ,跳转到 ParsingSQLRouter
在该类的route方法中我们可以看到
进入到 RoutingEngineFactory.newInstance 查看
它会进入我打断点的这个语句中
进入到 DefaultDatabaseRoutingEngine 可以看到它设置了两个值,其中shardingRule 就包含了dataSourceName的相关信息
查看shardingRule 是怎么设置值得
RoutingEngineFactory 类中 是通过入参获得的
ParsingSQLRouter 类中是通过构造参数复制的,
PreparedStatementRoutingEngine 类中也是通过构造函数给私有成员变量 shardingRouter 赋值的,
PreparedQueryShardingEngine 类中是通过在狗仔函数中给父类赋值的
ShardingPreparedStatement 类中通过 构造函数赋值
可以看到ShardingRule 最终是来自 ShardingConnection
再次追踪connection
它是被 SimpleExecutor 类调用的
也就是说它来源于 stmt,进去看看
BaseExecutor 类
SpringManagedTransaction 类中
在 DataSourceUtil 类中 doGetConnection 方法
这里获取 connnection 发现 没有相关的 dataSourceName。
然后思考了一下,好像没给表配置路由。