如何解決shardingsphere報(bào)錯(cuò)Missing?the?data?source?name:‘null‘
問(wèn)題描述
使用shardingsphere 嘗試進(jìn)行分庫(kù)時(shí),報(bào)錯(cuò) Missing the data source name: ‘null’
詳細(xì)錯(cuò)誤內(nèi)容
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 moreCaused 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
解決方法
你所插入的表 沒(méi)有配置相關(guān)的路由信息。
例如我的properties內(nèi)容如下
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 的路由規(guī)則,但是我測(cè)試數(shù)據(jù)插入的表是 user表。
由于沒(méi)有配置,所以定位不了數(shù)據(jù)庫(kù)。
如果更改一下,變成
那么就可以了
解決過(guò)程(個(gè)人記錄)
首先,最終拋出異常的地方 SQLExecutePrepareTemplate 類(lèi)
劃紅線的地方執(zhí)行出錯(cuò),進(jìn)去看一下內(nèi)容
劃紅線的地方出錯(cuò),因?yàn)閐ataSourceName 是null。
而這個(gè)入?yún)⑹窃赑reparedStatementExecutor中傳入的(下面的routeUnits)
它是被同類(lèi)下的(init 方法所調(diào)用)
它是被ShardingPreparedStatement 的 (initPreparedStatementExecutor 方法調(diào)用)
它是被同類(lèi)下的 (execute 方法調(diào)用)
定位可知,值是從該類(lèi)的私有變量 routeResult 中獲得的,而它是在shard() 方法中賦值的。
這里調(diào)用的是BaseShardingEngine
進(jìn)入route方法
BaseShardingEngine 抽象類(lèi)的抽象方法
進(jìn)入它的實(shí)現(xiàn)類(lèi) PreparedQueryShardingEngine
進(jìn)入到route,跳轉(zhuǎn)到 PreparedStatementRoutingEngine 類(lèi)
進(jìn)入到內(nèi)層route方法 中 ,跳轉(zhuǎn)到 ParsingSQLRouter
在該類(lèi)的route方法中我們可以看到
進(jìn)入到 RoutingEngineFactory.newInstance 查看
它會(huì)進(jìn)入我打斷點(diǎn)的這個(gè)語(yǔ)句中
進(jìn)入到 DefaultDatabaseRoutingEngine 可以看到它設(shè)置了兩個(gè)值,其中shardingRule 就包含了dataSourceName的相關(guān)信息
查看shardingRule 是怎么設(shè)置值得
- RoutingEngineFactory 類(lèi)中 是通過(guò)入?yún)@得的
- ParsingSQLRouter 類(lèi)中是通過(guò)構(gòu)造參數(shù)復(fù)制的,
- PreparedStatementRoutingEngine 類(lèi)中也是通過(guò)構(gòu)造函數(shù)給私有成員變量 shardingRouter 賦值的,
- PreparedQueryShardingEngine 類(lèi)中是通過(guò)在狗仔函數(shù)中給父類(lèi)賦值的
- ShardingPreparedStatement 類(lèi)中通過(guò) 構(gòu)造函數(shù)賦值
可以看到ShardingRule 最終是來(lái)自 ShardingConnection
再次追蹤connection
- PreparedStatementHandler 類(lèi)中
- 它是被 SimpleExecutor 類(lèi)調(diào)用的
也就是說(shuō)它來(lái)源于 stmt,進(jìn)去看看
BaseExecutor 類(lèi)
SpringManagedTransaction 類(lèi)中
在 DataSourceUtil 類(lèi)中 doGetConnection 方法
這里獲取 connnection 發(fā)現(xiàn) 沒(méi)有相關(guān)的 dataSourceName。
然后思考了一下,好像沒(méi)給表配置路由。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
在VSCode里使用Jupyter?Notebook調(diào)試Java代碼的詳細(xì)過(guò)程
Jupyter Notebook是以網(wǎng)頁(yè)的形式打開(kāi),可以在網(wǎng)頁(yè)頁(yè)面中直接編寫(xiě)代碼和運(yùn)行代碼,代碼的運(yùn)行結(jié)果也會(huì)直接在代碼塊下顯示的程序,這篇文章主要介紹了在VSCode里使用Jupyter?Notebook,調(diào)試Java代碼,需要的朋友可以參考下2022-07-07Java編程用兩個(gè)棧實(shí)現(xiàn)隊(duì)列代碼分享
這篇文章主要介紹了Java編程用兩個(gè)棧實(shí)現(xiàn)隊(duì)列代碼分享,具有一定參考價(jià)值,這里給大家分享下,供需要的朋友了解。2017-10-10Java實(shí)現(xiàn)簡(jiǎn)單畫(huà)畫(huà)畫(huà)板
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)簡(jiǎn)單畫(huà)畫(huà)畫(huà)板,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06Java生成訂單號(hào)或唯一id的高并發(fā)方案(4種方法)
本文主要介紹了Java生成訂單號(hào)或唯一id的高并發(fā)方案,包括4種方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-01-01Java請(qǐng)求轉(zhuǎn)發(fā)和請(qǐng)求重定向區(qū)別詳解
這篇文章主要介紹了Java請(qǐng)求轉(zhuǎn)發(fā)和請(qǐng)求重定向區(qū)別詳解,請(qǐng)求轉(zhuǎn)發(fā)和請(qǐng)求重定向,但二者是完全不同的,所以我們今天就來(lái)盤(pán)他們的區(qū)別介紹,需要的朋友可以參考一下2022-07-07淺談Java隨機(jī)數(shù)的原理、偽隨機(jī)和優(yōu)化
這篇文章主要介紹了淺談Java隨機(jī)數(shù)的原理、偽隨機(jī)和優(yōu)化,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-01-01基于servlet的執(zhí)行原理與生命周期(全面解析)
下面小編就為大家分享一篇servlet的執(zhí)行原理與生命周期全面解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2017-12-12Mybatis中SqlSession下的四大對(duì)象之執(zhí)行器(executor)
mybatis中sqlsession下的四大對(duì)象是指:executor, statementHandler,parameterHandler,resultHandler對(duì)象。這篇文章主要介紹了Mybatis中SqlSession下的四大對(duì)象之執(zhí)行器(executor),需要的朋友可以參考下2019-04-04Spring Profile與PropertyPlaceholderConfigurer項(xiàng)目多環(huán)境配置切換
這篇文章主要介紹了Spring Profile與PropertyPlaceholderConfigurer項(xiàng)目多環(huán)境配置切換方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09