Spring 4 JDBC - 如何加载数据库属性并进行优化(使用缓存或数据库连接池)

时间:2017-06-22 07:01:30

标签: spring spring-jdbc spring-cache

维护一个用Spring MVC 4.3.9.RELEASE(不是Spring Boot)编写的代码库......

在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-调度-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;
        }
}

userDAO的:

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使用相同的两个数据库配置文件执行相同的操作)!

问题(S):

  1. 这看起来非常不合适(好像应该做一次),如果war文件加载到Tomcat中,怎么能这样做(加载基于Spring的数据库配置文件)?

  2. 什么是性能提升的最佳技术(例如,我应该使用缓存系统还是数据库连接池)?

  3. 非常感谢任何建议......

2 个答案:

答案 0 :(得分:1)

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();
        }
    }

此代码非常危险,根据您的上下文大小,您最终会遇到问题。这里发生的是你在每次需要一个对象时加载整个应用程序,你将打开与db的连接(由于连接太多而最终会停止工作)你会遇到奇怪的事务问题并且可能(取决于大小) )记忆问题。 (当然,如果这是你想要的一切,那就这样继续)。

相反,你应该使用依赖注入。将所有需要的依赖项声明为字段,让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你的ContextLoaderListenerDispatcherServlet。现在这不是一个问题,但在你的情况下,两个类都加载相同的应用程序上下文,导致你的应用程序被加载两次,一个实例什么都不做。

ContextLoaderListener删除context-paramweb.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>        
</web-app>

现在在mvc-dispatcher-servlet.xml添加以下两行。

<import resource="classpath:sampledb.xml" />
<import resource="classpath:eventsdb.xml" />

或将两个文件的内容移至mvc-dispatcher-servlet.xml

答案 1 :(得分:0)

您可以使用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" />

on tomcat context.xml:

<ResourceLink auth="Container" global="jdbc/sampleDatabase" name="jdbc/sampleDatabase" type="javax.sql.DataSource"/>

以及您的UserDAO:

.....

@Autowired
@Qualifier("sampleDatabaseJdbcTemplate")
private JdbcTemplate sampleDatabaseJdbcTemplate;

...

您可以为第二个数据库执行相同的配置