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

猜你喜欢

转载自blog.csdn.net/zhou373986278/article/details/82779527