Spring 4 JDBC - 如何加载数据库属性和优化(使用缓存或数据库连接池)
Spring 4 JDBC - How to load DB Properties and optimize (using Cache or DB Connection Pool)
正在维护用 Spring MVC 4.3 编写的代码库。9.RELEASE(不是 Spring 引导)...
在src/main/resources之下:
有两个不同的数据库配置文件:
sampledb.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- Initialization for data source dbcp -->
<bean id="sampleDatabase" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
<property name="url"><value>jdbc:mysql://localhost/sampledb?zeroDateTimeBehavior=convertToNull</value></property>
<property name="username"><value>root/value></property>
<property name="password"><value></value></property>
<property name="maxIdle" value="10"/>
<property name="maxActive" value="50"/>
<property name="maxWait" value="100"/>
<property name="defaultAutoCommit" value="false"/>
<property name="removeAbandoned" value="true"/>
<property name="removeAbandonedTimeout" value="1"/>
<property name="minIdle" value="0"></property>
<property name="timeBetweenEvictionRunsMillis" value="1000"></property>
<property name="minEvictableIdleTimeMillis" value="1000"></property>
</bean>
</beans>
eventsdb.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- Initialization for data source dbcp -->
<bean id="eventsDatabase" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
<property name="url"><value>jdbc:mysql://localhost/eventsdb?zeroDateTimeBehavior=convertToNull</value></property>
<property name="username"><value>root</value></property>
<property name="password"><value></value></property>
<property name="maxIdle" value="10"/>
<property name="maxActive" value="50"/>
<property name="maxWait" value="100"/>
<property name="defaultAutoCommit" value="false"/>
<property name="removeAbandoned" value="true"/>
<property name="removeAbandonedTimeout" value="1"/>
<property name="minIdle" value="0"></property>
<property name="timeBetweenEvictionRunsMillis" value="1000"></property>
<property name="minEvictableIdleTimeMillis" value="1000"></property>
</bean>
</beans>
WEB-INF/web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>MyApp</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
WEB-INF/mvc-dispatcher-servlet.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<context:component-scan base-package="com.myapp.rest.controllers" />
<mvc:annotation-driven />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
示例网络服务代码:
package com.myapp.rest.controllers;
@Controller
@RequestMapping("/v2")
public class MyController {
@RequestMapping(value="users/{userId}",method=RequestMethod.GET)
public @ResponseBody Object getUserDetails(@PathVariable String userId){
Object response=null;
UserDAO dao = UserDAO.getInstance();
response=dao.getUser(userId);
return response;
}
}
用户道:
public class UserDAO {
private static UserDAO instance = null;
private JdbcTemplate jdbcTemplateObject = null;
public static UserDAO getInstance() {
if(instance == null) {
synchronized(UserDAO.class) {
if(instance == null) {
instance = new UserDAO();
}
}
}
return instance ;
}
UserDAO() {
try {
initializeDB();
}
catch(Exception e) {
e.printStackTrace();
}
}
private void initializeDB() {
try {
ApplicationContext context = new ClassPathXmlApplicationContext("sampledb.xml");
DataSource dataSource = (DataSource) context.getBean("sampleDatabase");
this.jdbcTemplateObject = new JdbcTemplate(dataSource);
}
catch (Exception e) {
e.printStackTrace();
}
}
// others methods which do the actual queries using Spring JDBC
}
之前的作者在每个 DAO 中都使用了这种模式(使用 ApplicationContext 初始化数据库)(代码库中有大约 20 个不同的 DAO,每个都使用相同的两个数据库配置文件做同样的事情)!
问题:
这似乎很不充分(似乎应该做一次),这个(加载基于 Spring 的数据库配置文件)如何在 war 后立即完成一次文件加载到 Tomcat?
提高性能的最佳技术是什么(例如,我应该使用缓存系统还是数据库连接池)?
非常感谢任何建议...
private void initializeDB() {
try {
ApplicationContext context = new ClassPathXmlApplicationContext("sampledb.xml");
DataSource dataSource = (DataSource) context.getBean("sampleDatabase");
this.jdbcTemplateObject = new JdbcTemplate(dataSource);
}
catch (Exception e) {
e.printStackTrace();
}
}
这段代码很危险,根据你上下文的大小,你最终会运行陷入问题。这里发生的是你每次需要一个对象时加载整个应用程序,你将打开到数据库的连接(由于连接太多最终将停止工作)你会遇到奇怪的事务问题并且可能(取决于大小) 内存问题。 (当然,如果那是你想要的,一定要像这样进行)。
相反,您应该使用依赖注入。将所有需要的依赖项声明为字段并让 spring 进行自动连接,这只会在启动时发生一次。
@Controller
@RequestMapping("/v2")
public class MyController {
private final UserDAO dao;
@Autowired
public MyController(UserDAO Dao) {
this.dao=dao;
}
@RequestMapping(value="users/{userId}",method=RequestMethod.GET)
public @ResponseBody Object getUserDetails(@PathVariable String userId){
return dao.getUser(userId);;
}
}
在你的 UserDAO
中做这样的事情。
@Repository
public class UserDAO {
private final JdbcTemplate jdbcTemplate;
@Autowired
public UserDAO(@Qualifier("sampleDatabase") DataSource dataSource) {
this.jdbcTemplate=new JdbcTemplate(dataSource);
}
// others methods which do the actual queries using Spring JDBC
}
另一件事是你的 web.xml
你们都有 ContextLoaderListener
和 DispatcherServlet
。现在这不一定是个问题,但在你的情况下 类 加载相同的应用程序上下文导致你的应用程序被加载两次,一个实例什么都不做。
从您的 web.xml
中删除 ContextLoaderListener
和 context-param
。
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>MyApp</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
现在在您的 mvc-dispatcher-servlet.xml
中添加以下 2 行。
<import resource="classpath:sampledb.xml" />
<import resource="classpath:eventsdb.xml" />
或者将两个文件的内容移动到mvc-dispatcher-servlet.xml
。
您可以使用 JNDI 配置,这是您的 App 和 Tomcat 之间的最佳实践:
在您的 xml 配置中:
<jee:jndi-lookup id="sampleDatabase" jndi-name="jdbc/sampleDatabase" />
<bean id="sampleDatabaseJdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="sampleDatabase" />
<property name="resultsMapCaseInsensitive" value="true" />
<property name="nativeJdbcExtractor" ref="nativeJdbcExtractor" />
</bean>
在您的 tomcat server.xml 上,您可以在 <GlobalNamingResources>
下添加以下资源
<Resource name="jdbc/sampleDatabase" auth="Container" global="jdbc/sampleDatabase" type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost/sampledb"
username="root" password="" maxActive="50" maxWait="-1" maxIdle="10"
validationQuery="SELECT 1 FROM DUAL" testOnBorrow="TRUE" />
在 tomcat context.xml :
<ResourceLink auth="Container" global="jdbc/sampleDatabase" name="jdbc/sampleDatabase" type="javax.sql.DataSource"/>
还有你的 UserDAO:
.....
@Autowired
@Qualifier("sampleDatabaseJdbcTemplate")
private JdbcTemplate sampleDatabaseJdbcTemplate;
...
您可以对第二个数据库进行相同的配置
正在维护用 Spring MVC 4.3 编写的代码库。9.RELEASE(不是 Spring 引导)...
在src/main/resources之下:
有两个不同的数据库配置文件:
sampledb.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- Initialization for data source dbcp -->
<bean id="sampleDatabase" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
<property name="url"><value>jdbc:mysql://localhost/sampledb?zeroDateTimeBehavior=convertToNull</value></property>
<property name="username"><value>root/value></property>
<property name="password"><value></value></property>
<property name="maxIdle" value="10"/>
<property name="maxActive" value="50"/>
<property name="maxWait" value="100"/>
<property name="defaultAutoCommit" value="false"/>
<property name="removeAbandoned" value="true"/>
<property name="removeAbandonedTimeout" value="1"/>
<property name="minIdle" value="0"></property>
<property name="timeBetweenEvictionRunsMillis" value="1000"></property>
<property name="minEvictableIdleTimeMillis" value="1000"></property>
</bean>
</beans>
eventsdb.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- Initialization for data source dbcp -->
<bean id="eventsDatabase" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
<property name="url"><value>jdbc:mysql://localhost/eventsdb?zeroDateTimeBehavior=convertToNull</value></property>
<property name="username"><value>root</value></property>
<property name="password"><value></value></property>
<property name="maxIdle" value="10"/>
<property name="maxActive" value="50"/>
<property name="maxWait" value="100"/>
<property name="defaultAutoCommit" value="false"/>
<property name="removeAbandoned" value="true"/>
<property name="removeAbandonedTimeout" value="1"/>
<property name="minIdle" value="0"></property>
<property name="timeBetweenEvictionRunsMillis" value="1000"></property>
<property name="minEvictableIdleTimeMillis" value="1000"></property>
</bean>
</beans>
WEB-INF/web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>MyApp</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
WEB-INF/mvc-dispatcher-servlet.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<context:component-scan base-package="com.myapp.rest.controllers" />
<mvc:annotation-driven />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
示例网络服务代码:
package com.myapp.rest.controllers;
@Controller
@RequestMapping("/v2")
public class MyController {
@RequestMapping(value="users/{userId}",method=RequestMethod.GET)
public @ResponseBody Object getUserDetails(@PathVariable String userId){
Object response=null;
UserDAO dao = UserDAO.getInstance();
response=dao.getUser(userId);
return response;
}
}
用户道:
public class UserDAO {
private static UserDAO instance = null;
private JdbcTemplate jdbcTemplateObject = null;
public static UserDAO getInstance() {
if(instance == null) {
synchronized(UserDAO.class) {
if(instance == null) {
instance = new UserDAO();
}
}
}
return instance ;
}
UserDAO() {
try {
initializeDB();
}
catch(Exception e) {
e.printStackTrace();
}
}
private void initializeDB() {
try {
ApplicationContext context = new ClassPathXmlApplicationContext("sampledb.xml");
DataSource dataSource = (DataSource) context.getBean("sampleDatabase");
this.jdbcTemplateObject = new JdbcTemplate(dataSource);
}
catch (Exception e) {
e.printStackTrace();
}
}
// others methods which do the actual queries using Spring JDBC
}
之前的作者在每个 DAO 中都使用了这种模式(使用 ApplicationContext 初始化数据库)(代码库中有大约 20 个不同的 DAO,每个都使用相同的两个数据库配置文件做同样的事情)!
问题:
这似乎很不充分(似乎应该做一次),这个(加载基于 Spring 的数据库配置文件)如何在 war 后立即完成一次文件加载到 Tomcat?
提高性能的最佳技术是什么(例如,我应该使用缓存系统还是数据库连接池)?
非常感谢任何建议...
private void initializeDB() {
try {
ApplicationContext context = new ClassPathXmlApplicationContext("sampledb.xml");
DataSource dataSource = (DataSource) context.getBean("sampleDatabase");
this.jdbcTemplateObject = new JdbcTemplate(dataSource);
}
catch (Exception e) {
e.printStackTrace();
}
}
这段代码很危险,根据你上下文的大小,你最终会运行陷入问题。这里发生的是你每次需要一个对象时加载整个应用程序,你将打开到数据库的连接(由于连接太多最终将停止工作)你会遇到奇怪的事务问题并且可能(取决于大小) 内存问题。 (当然,如果那是你想要的,一定要像这样进行)。
相反,您应该使用依赖注入。将所有需要的依赖项声明为字段并让 spring 进行自动连接,这只会在启动时发生一次。
@Controller
@RequestMapping("/v2")
public class MyController {
private final UserDAO dao;
@Autowired
public MyController(UserDAO Dao) {
this.dao=dao;
}
@RequestMapping(value="users/{userId}",method=RequestMethod.GET)
public @ResponseBody Object getUserDetails(@PathVariable String userId){
return dao.getUser(userId);;
}
}
在你的 UserDAO
中做这样的事情。
@Repository
public class UserDAO {
private final JdbcTemplate jdbcTemplate;
@Autowired
public UserDAO(@Qualifier("sampleDatabase") DataSource dataSource) {
this.jdbcTemplate=new JdbcTemplate(dataSource);
}
// others methods which do the actual queries using Spring JDBC
}
另一件事是你的 web.xml
你们都有 ContextLoaderListener
和 DispatcherServlet
。现在这不一定是个问题,但在你的情况下 类 加载相同的应用程序上下文导致你的应用程序被加载两次,一个实例什么都不做。
从您的 web.xml
中删除 ContextLoaderListener
和 context-param
。
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>MyApp</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
现在在您的 mvc-dispatcher-servlet.xml
中添加以下 2 行。
<import resource="classpath:sampledb.xml" />
<import resource="classpath:eventsdb.xml" />
或者将两个文件的内容移动到mvc-dispatcher-servlet.xml
。
您可以使用 JNDI 配置,这是您的 App 和 Tomcat 之间的最佳实践:
在您的 xml 配置中:
<jee:jndi-lookup id="sampleDatabase" jndi-name="jdbc/sampleDatabase" />
<bean id="sampleDatabaseJdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="sampleDatabase" />
<property name="resultsMapCaseInsensitive" value="true" />
<property name="nativeJdbcExtractor" ref="nativeJdbcExtractor" />
</bean>
在您的 tomcat server.xml 上,您可以在 <GlobalNamingResources>
<Resource name="jdbc/sampleDatabase" auth="Container" global="jdbc/sampleDatabase" type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost/sampledb"
username="root" password="" maxActive="50" maxWait="-1" maxIdle="10"
validationQuery="SELECT 1 FROM DUAL" testOnBorrow="TRUE" />
在 tomcat context.xml :
<ResourceLink auth="Container" global="jdbc/sampleDatabase" name="jdbc/sampleDatabase" type="javax.sql.DataSource"/>
还有你的 UserDAO:
.....
@Autowired
@Qualifier("sampleDatabaseJdbcTemplate")
private JdbcTemplate sampleDatabaseJdbcTemplate;
...
您可以对第二个数据库进行相同的配置