[Step by step Spring MVC](二)搭建之【引入jdbcTemplate】

前提: 上一节,完成了Spring MVC无DB Demo, 这一节会引入jdbcTemplate来构建数据库查询

1. 准备:

安装Mysql 5.7.21,在mysql bench中可以使用SQL查询到自己安装的version:  

select version();

2. 配置jdbcTemplate所需数据库信息

(1) 使用jdbc.properties文件来配置数据库信息

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/estore
jdbc.username=clops
jdbc.password=cscocmse

(2) jdbcTemplate会选用dbcp数据库连接池作为DataSource,使用spring-datasource.xml配置数据库连接池详细信息

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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">
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="initialSize" value="10" />
        <property name="maxActive" value="1000" />
    </bean>
    <context:property-placeholder location="classpath:jdbc.properties"/>
</beans>

其中<context:property-placeholder location>是为了让spring找到jdbc.properties文件

(3) 在spring-dao.xml中使用spring IOC 将datasource注入到jdbcTemplate实例中:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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">
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
</beans>

(4) 需要在web.xml中配置spring的contextloarderlistener以及 spring配置文件路径,便于tomcat启动加载    

 <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath*:spring/*.xml
        </param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

(5) 文件目录格式:


3. 在java中可以正常使用jdbcTemplate做数据库的增删该查动作了:

(1) 创建dao的package, 在dao中创建Interface UserDao, 创建实现类UserDaoImp

UserDao:

package com.cisco.eStore.dao;

import com.cisco.eStore.model.User;

import java.util.List;

public interface UserDao {
    public void saveOrUpdate(User user);

    public void delete(int uuid);

    public User get(int uuid);

    public List<User> list();
}


UserDaoImp:

package com.cisco.eStore.dao;

import com.cisco.eStore.dao.UserDao;
import com.cisco.eStore.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class UserDaoImp implements UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public User get(int uuid) {
        List<Map<String, Object>> list = jdbcTemplate.queryForList("select name from user");
        User user = new User();
        for(int i=0; i<list.size(); i++){
            Map<String, Object> rs= list.get(i);
            user.setName((String)rs.get("name"));
        }
        return user;
    }

    public void saveOrUpdate(User user) {
        List list = jdbcTemplate.queryForList("select name from user");
    }

    public void delete(int uuid) { }

    public List<User> list() {
        return null;
    }
}

这里Spring还提供了一种类似ORM的实现方式,就是手工写RowMapping,来将查询结果映射成相应的对象,具体方法如下:

建立UserRowMapper类:

package com.cisco.eStore.entity;

import com.cisco.eStore.model.User;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.lang.Nullable;

import java.sql.ResultSet;
import java.sql.SQLException;

public class UserRowMapper implements RowMapper<User> {
    @Nullable
    public User mapRow(ResultSet resultSet, int i) throws SQLException {
        User user = new User();
        user.setName(resultSet.getString("name"));
        user.setPassword(resultSet.getString("password"));
        return user;
    }
}

将上述jdbcTemplate.query加入RowMapper对象,返回值即为RowMapper中mapRow()定义的返回值,如:

 public User get(int uuid) {
        List<User> list = jdbcTemplate.query("select name, password from user", new UserRowMapper());
        return list.get(0);
    }

(2) 在Controller中引入UserDao自动注入实例,同时调用UserDao.get(uuid)方法,这样第一个spring mvc的数据库完成。

HelloworldController:

package com.cisco.eStore.controller;

import com.cisco.eStore.dao.UserDao;
import com.cisco.eStore.exception.BusinessException;
import com.cisco.eStore.model.User;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/admin")
public class HelloWorldController {

    static Logger logger = Logger.getLogger(HelloWorldController.class);

    @Autowired
    private UserDao userDao;

    @RequestMapping(value = "/user", method = RequestMethod.GET)
    public ModelAndView user(){
        return new ModelAndView("user", "command", new User());
    }

    @RequestMapping(value = "/addUser", method = RequestMethod.POST)
    @ExceptionHandler({BusinessException.class})
    public String addUser(@ModelAttribute("SpringWeb")User user, ModelMap model){
        if(StringUtils.isEmpty(user.getName())){
            throw new BusinessException("The user Name is null");
        }
        logger.info("Hello world log test");

        User users = userDao.get(1);


        model.addAttribute("name", user.getName());
        model.addAttribute("password", user.getPassword());
        model.addAttribute("email", user.getEmail());
        return "result";
    }

}

4. 思考:

(1) DataSource里的数据库连接池是否只初始化一份? 

R: 默认配置在spring-datasource.xml中的datasource, Scope是Singleton(单例),也就是说在这个spring ioc 容器中,只有一份DataSource可供使用, 当然你可以选择配置成Prototype类型,不过针对每个需要注入datasource的对象都会重新生成一个实例,可能会产生意想不到的错误。

(2) JdbcTemplate里如何使用connection, 每个实例都会建立一个connection么,如何保证数据库连接池的分配连接功能?如何释放连接?

R: JdbcTemplate.queryforList()底层源码,使用的还是最原始的数据库查询方式,代码如下:

 public <T> T execute(StatementCallback<T> action) throws DataAccessException {
        Assert.notNull(action, "Callback object must not be null");
        Connection con = DataSourceUtils.getConnection(this.obtainDataSource());
        Statement stmt = null;

        Object var11;
        try {
            stmt = con.createStatement();
            this.applyStatementSettings(stmt);
            T result = action.doInStatement(stmt);
            this.handleWarnings(stmt);
            var11 = result;
        } catch (SQLException var9) {
            String sql = getSql(action);
            JdbcUtils.closeStatement(stmt);
            stmt = null;
            DataSourceUtils.releaseConnection(con, this.getDataSource());
            con = null;
            throw this.translateException("StatementCallback", sql, var9);
        } finally {
            JdbcUtils.closeStatement(stmt);
            DataSourceUtils.releaseConnection(con, this.getDataSource());
        }

        return var11;
    }
在获取Connection的时候,会多加一步事务判断

(3) Spring默认的模式 是Singleton 单例模式,还是每个注入都是新new的对象?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值