如何在Spring启动时只执行一次SQL脚本?

时间:2013-07-01 20:21:34

标签: spring jersey spring-jdbc

我有一个基于Spring JDBC和Jersey RESTful Web服务的Web应用程序。我使用以下Spring JDBC模板类来启动dataSource并执行SQL脚本(update_condition_table.sql):

public class CustomerJDBCTemplate implements CustomerDAO {
    private DataSource dataSource;
    private JdbcTemplate jdbcTemplateObject;

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
        this.jdbcTemplateObject = new JdbcTemplate(dataSource);
        Resource rc = new ClassPathResource("update_condition_table.sql");
        JdbcTestUtils.executeSqlScript(jdbcTemplateObject, rc, false);
    }

    // ......other methods
}

bean配置文件是beans.xml:

<!-- Initialization for data source -->
<bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost:3306/customer" />
    <property name="username" value="root" />
    <property name="password" value="mypassword" />
</bean>

<!-- Definition for customerJDBCTemplate bean -->
<bean id="customerJDBCTemplate" class="com.example.db.CustomerJDBCTemplate">
    <property name="dataSource" ref="dataSource" />
</bean>

Jersey控制器类包含类CustomerJDBCTemplate的实例化,并用作REST Web服务:

@Path("/customer")
public class CustomerService {

    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    CustomerJDBCTemplate dbController = (CustomerJDBCTemplate) context.getBean("customerJDBCTemplate");

    // ... some GET/POST methods
}

当我通过在浏览器中输入索引URL来启动我的Web应用程序时,SQL脚本由customerJDBCTemplate bean执行。但是,当我单击导航到其他页面时,它崩溃并报告无法再次执行SQL脚本。显然,在初始化dataSource并初始启动索引网页后,SQL脚本再次被执行。如何通过在Web应用程序初次启动时仅运行一次SQL脚本来避免这种情况?

看起来我需要将bean实例化代码移出CustomerService类,但是我应该把代码放在哪里?

2 个答案:

答案 0 :(得分:1)

我认为我应该将bean应用程序上下文设置为CustomerService类中的静态,并在静态初始化块中执行,如下所示:

@Path("/customer")
public class CustomerService {

    private static ApplicationContext context;
    private static CustomerJDBCTemplate dbController;

    static {
        context = new ClassPathXmlApplicationContext("beans.xml");
        dbController = (CustomerJDBCTemplate) context.getBean("customerJDBCTemplate");
    }

    //... other methods
}

我想原因是Jersey为每个HTTP会话创建了一个不同的CustomerService实例(如果我错了,请纠正我)。因此,如果我将bean上下文设置为实例变量,它将为每个HTTP请求执行初始化。

答案 1 :(得分:0)

让您的CustomerJDBCTemplate实施InitializingBean。在Spring的BeanFactory设置了所有属性后,afterPropertiesSet将被调用一次。

例如:

public class CustomerJDBCTemplate implements CustomerDAO, InitializingBean {
  ... 
  // ......other methods

  public void afterPropertiesSet() throws Exception {
    //do your initializing, or call your initializing methods
  }
}