shardingsphere 报错 Missing the data source name: ‘null‘

问题描述

使用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表。由于没有配置,所以定位不了数据库。如果更改一下,变成
shardingsphere 报错 Missing the data source name: ‘null‘_第1张图片
那么就可以了

解决过程(个人记录)

首先,最终抛出异常的地方 SQLExecutePrepareTemplate

shardingsphere 报错 Missing the data source name: ‘null‘_第2张图片
划红线的地方执行出错,进去看一下内容
shardingsphere 报错 Missing the data source name: ‘null‘_第3张图片
划红线的地方出错,因为dataSourceName 是null。
而这个入参是在PreparedStatementExecutor中传入的(下面的routeUnits)
shardingsphere 报错 Missing the data source name: ‘null‘_第4张图片
它是被同类下的(init 方法所调用)
shardingsphere 报错 Missing the data source name: ‘null‘_第5张图片
它是被ShardingPreparedStatement 的 (initPreparedStatementExecutor 方法调用)
在这里插入图片描述
它是被同类下的 (execute 方法调用)
shardingsphere 报错 Missing the data source name: ‘null‘_第6张图片
定位可知,值是从该类的私有变量 routeResult 中获得的,而它是在shard() 方法中赋值的。
在这里插入图片描述
这里调用的是BaseShardingEngine
shardingsphere 报错 Missing the data source name: ‘null‘_第7张图片
进入route方法
BaseShardingEngine 抽象类的抽象方法
在这里插入图片描述
进入它的实现类 PreparedQueryShardingEngine
在这里插入图片描述
进入到route,跳转到 PreparedStatementRoutingEngine 类
shardingsphere 报错 Missing the data source name: ‘null‘_第8张图片
进入到内层route方法 中 ,跳转到 ParsingSQLRouter
在该类的route方法中我们可以看到
shardingsphere 报错 Missing the data source name: ‘null‘_第9张图片
进入到 RoutingEngineFactory.newInstance 查看
shardingsphere 报错 Missing the data source name: ‘null‘_第10张图片
它会进入我打断点的这个语句中
进入到 DefaultDatabaseRoutingEngine 可以看到它设置了两个值,其中shardingRule 就包含了dataSourceName的相关信息
shardingsphere 报错 Missing the data source name: ‘null‘_第11张图片
查看shardingRule 是怎么设置值得

  • RoutingEngineFactory 类中 是通过入参获得的

  • ParsingSQLRouter 类中是通过构造参数复制的,

  • PreparedStatementRoutingEngine 类中也是通过构造函数给私有成员变量 shardingRouter 赋值的,

  • PreparedQueryShardingEngine 类中是通过在狗仔函数中给父类赋值的

  • ShardingPreparedStatement 类中通过 构造函数赋值
    shardingsphere 报错 Missing the data source name: ‘null‘_第12张图片
    可以看到ShardingRule 最终是来自 ShardingConnection
    再次追踪connection

  • PreparedStatementHandler 类中
    shardingsphere 报错 Missing the data source name: ‘null‘_第13张图片

  • 它是被 SimpleExecutor 类调用的
    shardingsphere 报错 Missing the data source name: ‘null‘_第14张图片
    也就是说它来源于 stmt,进去看看
    shardingsphere 报错 Missing the data source name: ‘null‘_第15张图片
    BaseExecutor 类
    shardingsphere 报错 Missing the data source name: ‘null‘_第16张图片
    SpringManagedTransaction 类中
    shardingsphere 报错 Missing the data source name: ‘null‘_第17张图片
    在 DataSourceUtil 类中 doGetConnection 方法
    shardingsphere 报错 Missing the data source name: ‘null‘_第18张图片
    这里获取 connnection 发现 没有相关的 dataSourceName。

然后思考了一下,好像没给表配置路由。

你可能感兴趣的:(日常犯蠢,数据库,mysql,数据库)