[英]Getting a java.lang.NullPointerException with Spring Boot JdbcTemplate
General Information: New to Spring Boot and wanted to test out my JDBC connections via unit tests.一般信息: Spring Boot 新手,想通过单元测试测试我的 JDBC 连接。 I made a simple class to connect to my database and a simple test class to follow up with the proper test case.
我做了一个简单的类来连接到我的数据库和一个简单的测试类来跟进正确的测试用例。
Problem: Continuously receiving a java.lang.NullPointerException when performing jdbcTemplate.getDataSource().getConnection();
问题:执行
jdbcTemplate.getDataSource().getConnection();
时不断收到 java.lang.NullPointerException jdbcTemplate.getDataSource().getConnection();
I am having a hard time understanding why.我很难理解为什么。 I tried using different databases, and ensured that I could make a connection with the regular JDBC.
我尝试使用不同的数据库,并确保可以与常规 JDBC 建立连接。 I have referred to numerous other questions on Stack Overflow but I have still been stuck on this for the past two days without any progress.
我已经在 Stack Overflow 上提到了许多其他问题,但过去两天我仍然被困在这个问题上,没有任何进展。 I even tried to use different types of DataSource libraries but all of them yield the same result.
我什至尝试使用不同类型的 DataSource 库,但它们都产生相同的结果。
Question: How do I solve this?问题:我该如何解决这个问题? If anyone can also explain why the issue is happening, and why do we need to use the Spring JDBC on an enterprise level, that would be great.
如果有人也能解释为什么会出现这个问题,以及为什么我们需要在企业级别使用 Spring JDBC,那就太好了。
My code:我的代码:
DatabaseTableService.java数据库表服务.java
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.vertica.jdbc.DataSource;
@RestController
@RequestMapping("/databaseServices")
public class DatabaseTableService {
private JdbcTemplate jdbcTemplate;
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource= dataSource;
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
@RequestMapping("/testConnection")
@ResponseBody
public boolean canConnectToDB() {
boolean result;
try {
jdbcTemplate.getDataSource().getConnection();
result = true;
} catch (Exception e) {
e.printStackTrace();
result = false;
}
return result;
}
} }
beans.xml bean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.company.project"></context:component-scan>
<mvc:annotation-driven/>
<bean id="dataSource"
class="com.vertica.jdbc.DataSource">
<property name="URL" value="DBURLHERE"/>
<property name="userID" value="USERIDHERE"/>
<property name="password" value="PASSWORDHERE"/>
</bean>
<bean id="databaseTableService"
class="com.company.project.services.DatabaseTableService">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
DatabaseTableServiceTest.java数据库表服务测试.java
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import com.vertica.jdbc.DataSource;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ApplicationController.class)
@WebAppConfiguration
public class DatabaseTableServiceTest {
@Autowired
private WebApplicationContext webApplicationContext;
private JdbcTemplate jdbcTemplate;
private MockMvc mockMvc;
DatabaseTableService databaseTableServiceObject;
DataSource testDataSource = new DataSource();
@Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.build();
databaseTableServiceObject = new DatabaseTableService();
}
@Test
public void setDataSource() throws Exception {
databaseTableServiceObject.setDataSource(testDataSource);
}
@Test
public void validateCanConnectToDB() throws Exception {
Assert.assertTrue(databaseTableServiceObject.canConnectToDB());
}
@After
public void tearDown() throws Exception {
mockMvc = null;
databaseTableServiceObject = null;
testDataSource = null;
}
}
ApplicationController.java应用程序控制器.java
import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.*;
import org.springframework.web.bind.annotation.*;
@SpringBootApplication
@ImportResource({"beans.xml"})
@ComponentScan(basePackages = "com.company.project")
public class ApplicationController {
public static void main(String[] args) throws Exception {
SpringApplication.run(ApplicationController.class, args);
}
}
Folder Structure文件夹结构
You are using Spring Boot and next try very hard not to.您正在使用 Spring Boot,接下来非常努力地不使用。 Remove your
beans.xml
and the @ImportResource
from your ApplicationController
(which isn't a controller but your actual application btw, as your service is your actual controller).从
ApplicationController
删除beans.xml
和@ImportResource
(顺便说一下,它不是控制器,而是您的实际应用程序,因为您的服务是您的实际控制器)。 Also assuming that your ApplicationController
is in the same package you can remove the @ComponentScan
as well.还假设您的
ApplicationController
在同一个包中,您也可以删除@ComponentScan
。
Then in your application.properties
add the following然后在您的
application.properties
添加以下内容
spring.datasource.url=<your-url>
spring.datasource.username=<your-username>
spring.datasource.password=<your-password>
spring.datasource.type=com.vertica.jdbc.DataSource
spring.mvc.view.prefix=/WEB-INF/
spring.mvc.view.suffix=.jsp
Spring Boot will create a DataSource
and a JdbcTemplate
for you, so no need to create that yourself. Spring Boot 将为您创建一个
DataSource
和一个JdbcTemplate
,因此无需自己创建。 Just @Autowire
the JdbcTemplate
in your class.只需
@Autowire
您班级中的JdbcTemplate
。
@RestController
@RequestMapping("/databaseServices")
public class DatabaseTableService {
private final JdbcTemplate jdbcTemplate;
@Autowired
public DatabaseTableService(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate=jdbcTeplate;
}
@RequestMapping("/testConnection")
@ResponseBody
public boolean canConnectToDB() {
boolean result;
try {
jdbcTemplate.getDataSource().getConnection();
result = true;
} catch (Exception e) {
e.printStackTrace();
result = false;
}
return result;
}
}
Now your test, it is quite a mess.现在你的测试,真是一团糟。 You are using Spring but are doing things yourself, so not sure what you are trying to achieve there.
您正在使用 Spring 但正在自己做事,因此不确定您要在那里实现什么。
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ApplicationController.class)
@WebAppConfiguration
public class DatabaseTableServiceTest {
@Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
private DatabaseTableService databaseTableServiceObject;
@Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.build();
}
@Test
public void setDataSource() throws Exception {
databaseTableServiceObject.setDataSource(testDataSource);
}
@Test
public void validateCanConnectToDB() throws Exception {
Assert.assertTrue(databaseTableServiceObject.canConnectToDB());
}
}
You can just @Autowired
the service which is now fully constructed.您可以只
@Autowired
现在完全构建的服务。
Final thing is that your canConnectToDB
method is flawed.最后一点是您的
canConnectToDB
方法有缺陷。 You are obtaining a connection but are never returning/closing it.您正在获取连接但从未返回/关闭它。 So after calling this method for a couple of times your application will stop work as the connection pool will be depleted or your database stops accepting connections.
因此,在多次调用此方法后,您的应用程序将停止工作,因为连接池将耗尽或您的数据库停止接受连接。
In short work with the framework instead of against/around the framework.简而言之,使用框架而不是反对/围绕框架。 Read the documentation instead of trying to hack your way around it.
阅读文档而不是试图破解它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.