spring報錯:ORA-01017: invalid username/password; logon denied

今天在整合spring和mybatis時進行測試,發現sql查詢時連不上數據庫,異常日誌如下:

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is org.apache.commons.dbcp.SQLNestedException: Cannot create PoolableConnectionFactory (ORA-01017: invalid username/password; logon denied
)
### The error may exist in com/summerzhou/base/mapper/SysuserMapper.xml
### The error may involve com.summerzhou.base.mapper.SysuserMapper.selectByPrimaryKey
### The error occurred while executing a query
### Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is org.apache.commons.dbcp.SQLNestedException: Cannot create PoolableConnectionFactory (ORA-01017: invalid username/password; logon denied
)
	at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:75)
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:371)
	at com.sun.proxy.$Proxy3.selectOne(Unknown Source)
	at org.mybatis.spring.SqlSessionTemplate.selectOne(SqlSessionTemplate.java:163)
	at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:63)
	at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:43)
	at com.sun.proxy.$Proxy4.selectByPrimaryKey(Unknown Source)
	at com.summerzhou.test.TestClass.findUserById(TestClass.java:27)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)

這裏提示是用戶/密碼無效,我在oracle上試了試,密碼是正確的。然後檢查db.properties,其中的用戶名密碼也沒錯

driverClassName=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@192.168.25.129:1521:orcl
username=tommy
password=***

使用spring框架獲取dataSource實例,檢查dataSource的userName,發現結果爲x,並不是db文件中指定的tommy。

    @Test
    public void setDateSource() {
		BasicDataSource dataSource = (BasicDataSource) applicationContext.getBean("dataSource");
		System.out.println(dataSource.getUsername());
    }

我突然意識到,x就是我本機的用戶名,查了查資料,spring框架的<context:property-placeholder>是用來激活“${}”佔位符的,解析location屬性中定義的文件,生成了一個PropertyPlaceholderConfigurer實例, PropertyPlaceholderConfigurer用來外部化根據java properties格式定義的屬性,可以使程序員定製特定的環境屬性,如數據庫url和密碼,這樣可以只修改對應的properties文件,而無需影響框架。
在我定義的db.properties中,用戶名的key爲username,dataSource注入的屬性值爲${username},但其實這個username並不是文件中的值。因爲PropertyPlaceholderConfigurer不僅在指定的properties文件中定義屬性,還會檢查java運行環境中的屬性。我們可以通過system-properties-mode屬性來定製檢查屬性的順序,該屬性有四個值:
1)ENVIRONMENT:默認屬性,首先在運行環境中讀取,如果沒有得到指定的屬性值,則在location指定的properties文件中讀取。這也是dataSource的用戶名爲什麼爲本機名的原因,因爲在運行系統中,username爲系統本機名
2)NONE:從不檢查系統屬性,只解析properties文件
3)OVERRIDE:先系統後本地properties
4)FALLBACK:先properties後系統

綜上,解決方法有兩種:
1.將properties文件中的key之前全加上jdbc.,這樣在讀取屬性時就不會與系統屬性衝突

jdbc.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@192.168.25.129:1521:orcl
jdbc.username=tommy
jdbc.password=****

dataSource注入改爲:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
	<property name="driverClassName" value="${jdbc.driverClassName}"></property>
	<property name="url" value="${jdbc.url}"></property>
	<property name="username" value="${jdbc.username}"></property>
	<property name="password" value="${jdbc.password}"></property>
</bean>

2.將<context:property-placeholder>的system-properties-mode改爲NONE或者FALLBACK

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章