Spring使用计算机名而不是提供的用户名来访问jdbc数据库

Posted

技术标签:

【中文标题】Spring使用计算机名而不是提供的用户名来访问jdbc数据库【英文标题】:Spring use Computer name instead of supplied username for jdbc database access 【发布时间】:2020-02-14 11:17:56 【问题描述】:

阅读 Pro Spring 5,一个显示 Spring JDBC 正在使用 mysql DB 的示例。我使用本书的源代码。这是代码

@Configuration
@PropertySource("classpath:db/jdbc2.properties")
@ComponentScan(basePackages = "com.apress.prospring5.ch6")
public class AppConfig 

    private static Logger logger = LoggerFactory.getLogger(AppConfig.class);
    @Value("$driverClassName")
    private String driverClassName;
    @Value("$url")
    private String url;
    @Value("$username")
    private String username;
    @Value("$password")
    private String password;

@Bean(destroyMethod = "close")
    public DataSource dataSource() 
        try 
            BasicDataSource dataSource = new BasicDataSource();
            dataSource.setDriverClassName(driverClassName);
            dataSource.setUrl(url);
            dataSource.setUsername(username);
            dataSource.setPassword(password);
            return dataSource;
         catch (Exception e) 
            logger.error("DBCP DataSource bean cannot be created!", e);
            return null;
        
    

jdbc2.properties

driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/musicdb?useSSL=true
username=prospring5
password=prospring5

测试

public class AnnotationJdbcTest 

    private GenericApplicationContext ctx;
    private SingerDao singerDao;

    @Before
    public void setUp() 
        ctx = new AnnotationConfigApplicationContext(AppConfig.class);
        singerDao = ctx.getBean(SingerDao.class);
        assertNotNull(singerDao);
    

    @Test
    public void testFindAll() 
        List<Singer> singers = singerDao.findAll();
        assertTrue(singers.size() == 3);
        listSingers(singers);
        ctx.close();
    

我的 MySQL 实例已经有用户 prospring5 以及创建和填充的架构

当我尝试运行 AnnotationJdbcTest 时,我得到了这个异常:

Failed to obtain JDBC Connection; nested exception is java.sql.SQLException: Cannot create PoolableConnectionFactory (Access denied for user 'Mehdi'@'localhost' (using password: YES))
org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLException: Cannot create PoolableConnectionFactory (Access denied for user 'Mehdi'@'localhost' (using password: YES))
    at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:82)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:612)

如您所见,该项目使用我的计算机名称“Mehdi”,而不是 .properties 文件中的名称“prospring5”。这是为什么?以及如何解决?

您可以自己下载源代码并从这里运行它:https://github.com/Apress/pro-spring-5 该项目是:第6章/spring-jdbc-annotations

编辑: 我按照@STaefi 的建议打印了值,这是输出:

com.mysql.cj.jdbc.Driver
jdbc:mysql://localhost:3306/musicdb?useSSL=false
Mehdi
prospring5

代码

@Bean()
    public DataSource dataSource() 
        try 
            BasicDataSource dataSource = new BasicDataSource();
            dataSource.setDriverClassName(driverClassName);
            System.out.println(driverClassName);
            dataSource.setUrl(url);
            System.out.println(url);
            dataSource.setUsername(username);
            System.out.println(username);
            dataSource.setPassword(password);
            System.out.println(password);
            return dataSource;

首先我尝试在初始化时设置这些值,但这并不好。但是在我使用username = "prospring5"; dataSource.setUsername(username); 之后它起作用了。那么这是什么意思。为什么Spring无法像成功加载url和密码一样加载用户名。

【问题讨论】:

早期的猜测,也许它在查找和加载您的属性文件时遇到了问题。您可以对用户名和密码进行硬编码以查看是否可以解决问题吗?您还可以记录应该从属性文件中读取的属性,以查看为它们加载的内容。 尝试将属性文件的路径更改为 @PropertySource("classpath:**/db/jdbc2.properties")。 @STaefi 我犯了同样的错误。我该怎么做你所说的日志记录? @lazy.coder 无法解析配置类 [com.apress.prospring5.ch6.config.AppConfig];嵌套异常是 java.io.FileNotFoundException: 类路径资源 [**/db/jdbc2.properties] 无法打开,因为它不存在,现在找不到属性文件。 这可能会帮助你***.com/questions/20353402。理想情况下,您的用户无法访问您的数据库。此外,如果您在本地系统中运行,您可以关闭 useSSL=flase。 【参考方案1】:

请您尝试将默认值设为:

@Value("$driverClassName:com.mysql.cj.jdbc.Driver")
private String driverClassName;
@Value("$url:jdbc:mysql://localhost:3306/musicdb?useSSL=true")
private String url;
@Value("$username:prospring5")
private String username;
@Value("$password:prospring5")
private String password;

并删除顶部的@PropertySource("classpath:db/jdbc2.properties")。如果这可行,那么您可以再次尝试使用 propertySource

【讨论】:

就像@usertest 所说,只需将用户名和密码更改为其他名称,它就可以工作 是的,我是用户测试,同样的人问这个问题。谢谢。【参考方案2】:

所以我通过简单地在 .propreties 文件中使用不同的字符串标识符解决了这个问题。我将其更改为 one=prospring5 并且有效。显然,使用名为“用户名”的属性将加载除您的计算机名称之外的任何内容。我不知道 Spring 是否提供了属性名称的禁止值列表。如果他们不这样做,他们当然应该考虑。

【讨论】:

禁止有点强;您遇到了一个使用非常模糊的属性名称的情况,该属性名称恰好已经由 Spring 组件设置。这就是为什么建议使用上下文驱动的属性名称,例如“musicdb.username”。 保留怎么样?我知道 MySQL 有很多 dev.mysql.com/doc/refman/8.0/en/keywords.html 。另外,我没有想到 Pro Spring 5 的书作者的名字。你自己检查源代码。 我的意思是避免使用模棱两可或通用的名称,我并不是在争论术语。顺便说一下,这对于您自己定义的 bean 的名称来说是双倍的。我已经被 Spring 升级咬了至少三次,我不得不解决重复的 bean 名称。这伤害了很多 bean 恰好在一个到处使用的共享库中。

以上是关于Spring使用计算机名而不是提供的用户名来访问jdbc数据库的主要内容,如果未能解决你的问题,请参考以下文章

使用基于主机名而不是 IP 地址的自签名证书保护 Python WebSocket

地名自动完成城市/州,返回完整的州名而不是缩写

NSStringFromSelector 返回变量名而不是变量值

在过程宏中,如何检查字符串是不是是有效的变量名而不是关键字?

实用程序 iptables 列出主机名而不是 IP 地址

Spring的事务抽象