Spring系列六:JdbcTemplate

JdbcTemplate

实际需求

实际需求: 如果程序员就希望使用spring框架来做项目, spring框架如何处理对数据库的操作呢?

  1. 方案1: 使用前面做项目开发的JdbcUtils
  2. 方案2: 其实spring提供了一个操作数据库(表)功能强大的类JdbcTemplate. 我们可以同ioc容器来配置一个jdbcTemplate对象, 使用它来完成对数据库表的各种操作.

官方文档

官方文档: spring-framework-5.3.8\docs\javadoc-api\index.html

Spring系列六:JdbcTemplate_第1张图片
Spring系列六:JdbcTemplate_第2张图片

基本介绍

1.通过Spring可以配置数据源, 从而完成对数据表的操作
2.JdbcTemplateSpring提供的访问数据库的技术. 可以将JDBC的常用操作封装为模板方法.

搭建环境

1.引入使用JdbcTemplate需要的jar包
Spring系列六:JdbcTemplate_第3张图片


2.创建数据库spring和表monster

1)管理员打开cmd窗口, 开启数据库服务. 别忘了, 这很重要 安装Mysql5.7
Spring系列六:JdbcTemplate_第4张图片

2)sql代码

-- 创建数据库
CREATE DATABASE spring;
USE spring;
-- 创建表
CREATE TABLE monster (
	id INT UNSIGNED PRIMARY KEY,
	`name` VARCHAR(64) NOT NULL DEFAULT '',
	skill VARCHAR(64) NOT NULL DEFAULT ''
)CHARSET=utf8;
INSERT INTO monster VALUES(100, '孙悟空', '金箍棒');
INSERT INTO monster VALUES(200, '红孩儿', '三昧真火');
INSERT INTO monster VALUES(300, '铁扇公主', '芭蕉扇');

配置DataSource


3.创建配置文件 src/dbc.properties
JdbcTemplate会使用到DataSource, 而DataSource可以拿到连接去操作数据库
找到前面我们搭建的spring项目, 在src下新建jdbc.properties
Spring系列六:JdbcTemplate_第5张图片

jdbc.user=root
jdbc.pwd=zzw
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring

4.创建配置文件 src/JdbcTemplate_ioc.xml
通过属性文件配置bean
Spring系列六:JdbcTemplate_第6张图片

JdbcTemplate_ioc.xml


<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.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    
    <context:property-placeholder location="classpath:jdbc.properties"/>
    
    <bean class="com.mchange.v2.c3p0.ComboPooledDataSource" id="dataSource">
        
        <property name="user" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.pwd}"/>
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
    bean>
beans>

5.在com.zzw.spring.test包下新建测试类JdbcTemplateTest

public class JdbcTemplateTest {
    @Test
    public void testDataSourceByJdbcTemplate() {
        //获取容器
        ApplicationContext ioc =
                new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");
		//在这里打个断点
        System.out.println("ok");
    }
}

Spring系列六:JdbcTemplate_第7张图片
Spring系列六:JdbcTemplate_第8张图片

public class JdbcTemplateTest {
    @Test
    public void testDataSourceByJdbcTemplate() {
        //获取容器
        ApplicationContext ioc =
                new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");

        //因为ComboPooledDataSource类实现了DataSource接口, 所以我们可以用接口类型来获取 comboPooledDataSource对象
        DataSource dataSource = ioc.getBean(DataSource.class);
        Connection connection = dataSource.getConnection();
        
        //获取到connection=com.mchange.v2.c3p0.impl.NewProxyConnection@2cd2a21f
        System.out.println("获取到connection=" + connection);
        connection.close();
        System.out.println("ok");
    }
}

添加数据

6.配置JdbcTemplate_ioc.xml, 将数据源分配给JdbcTemplate bean

JdbcTemplate_ioc.xml


<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.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    
    <context:property-placeholder location="classpath:jdbc.properties"/>
    
    <bean class="com.mchange.v2.c3p0.ComboPooledDataSource" id="dataSource">
        
        <property name="user" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.pwd}"/>
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
    bean>

    
    
    <bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
        
        <property name="dataSource" ref="dataSource"/>
    bean>
beans>

测试通过JdbcTemplate对象完成添加数据

public class JdbcTemplateTest {
    @Test
    public void addDataByJdbcTemplate() {
        //获取到容器
        ApplicationContext ioc =
                new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");

        //获取JdbcTemplate对象, 这里我们先 debug一下
        System.out.println("ok");
    }
}

Spring系列六:JdbcTemplate_第9张图片

public class JdbcTemplateTest {
    @Test
    public void addDataByJdbcTemplate() {
        //获取到容器
        ApplicationContext ioc =
                new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");

        //获取JdbcTemplate对象 [按类型获取]
        JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);
        //1.添加方式①
        //String sql = "insert into monster values(400, '陆小千', '魔幻手机')";
        //jdbcTemplate.execute(sql);
        //2.添加方式② ?占位符, 可以防止sql注入
        String sql = "insert into monster values(?, ?, ?)";
        //affected表示 执行后表受影响的行数
        int affected = jdbcTemplate.update(sql, 500, "金角大王", "紫金红葫芦");

        System.out.println("add success afftected=" + affected);
    }
}

Spring系列六:JdbcTemplate_第10张图片

修改数据

public class JdbcTemplateTest {
    //测试通过JdbcTemplate对象完成修改数据
    @Test
    public void updateDataByJdbcTemplate() {
        //获取到容器
        ApplicationContext ioc =
                new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");

        //获取JdbcTemplate对象
        JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);

        //组织SQL
        String sql = "update monster set skill = ? where id = ?";
        //假使修改后的数据和修改前的数据一样, 也认为是修改成功了一条语句, affected返回 1, 因为它没有判断要修改的数据
        int affected = jdbcTemplate.update(sql, "美人计", 300);
        System.out.println("update ok affected=" + affected);
    }
}

批量处理

public class JdbcTemplateTest {
    //测试通过JdbcTemplate对象完成批量添加数据
    //这里有一个使用API的技巧

    /**
     * 说明
     * 1.对于某些类, 有很多API, 使用的buzhou
     * 2.使用技巧: (1)先确定API名字 (2)根据API提供相应的参数 [组织参数]
     *           (3)把自己的调用思路清晰 (4)根据API, 可以推测类的用法和功能
     */
    @Test
    public void addBatchDataByJdbcTemplate() {
        //获取到容器
        ApplicationContext ioc =
                new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");

        //获取JdbcTemplate对象
        JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);

        //1.先确定, 猜测API名称 update -> batchUpdate [如果出现问题,再重新找]
        //public int[] batchUpdate(String sql, List batchArgs){}
        //2.准备参数 [构建实参]
        String sql = "insert into monster values(?, ?, ?)";
        List<Object[]> batchArgs = new ArrayList<>();
        batchArgs.add(new Object[]{600, "鼠鼠", "偷吃粮食"});
        batchArgs.add(new Object[]{700, "猫猫", "抓老鼠"});
        //3.调用
        //说明: 返回结果是一个数组, 每个元素对应上面的sql语句对表的影响记录数
        int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
        //输出
        for (int anInt : ints) {
            System.out.println("anInt=" + anInt);
        }
        System.out.println("batch add ok~");
    }
}

查询后封装成对象

在spring项目中我们已经创建了Monster实体类

这里有一个知识点: 给字段起别名, 应对应实体类的属性. 我们在前面的家居购项目中遇到过

Spring系列六:JdbcTemplate_第11张图片

public class JdbcTemplateTest {
    /**
     * 查询id=100的monster对并封装到Monter实体对象[在实际开发中非常有用]
     */
    @Test
    public void selectDataByJdbcTemplate() {
        //获取到容器
        ApplicationContext ioc =
                new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");

        //获取JdbcTemplate对象
        JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);

        //1.确定API query -> queryForObject
        //public  T queryForObject(String sql, RowMapper rowMapper, @Nullable Object... args)
        //2.准备参数
        String sql = "SELECT id AS monsterId, `name`, skill FROM monster WHERE id = 100";
        //使用了RowMapper 接口来对返回的数据, 进行一个封装 底层使用的反射 -> setter方法
        //细节: 你查询的记录的表的字段需要和 Monster对象的字段名保持一致
        RowMapper<Monster> rowMapper = new BeanPropertyRowMapper<>();
        //3.调用
        Monster monster = jdbcTemplate.queryForObject(sql, rowMapper);
        //输出
        System.out.println("monster=" + monster);
        System.out.println("query ok~");
    }
}

结果报错: java.lang.IllegalStateException: Mapped class was not specified

修正代码

RowMapper<Monster> rowMapper = new BeanPropertyRowMapper<>(Monster.class);

运行结果
Spring系列六:JdbcTemplate_第12张图片

查询后封装成对象集合

Spring系列六:JdbcTemplate_第13张图片

public class JdbcTemplateTest {
    /**
     * 查询id>=200的monster并封装到Monster实体对象
     */
    @Test
    public void selectMulDataByJdbcTemplate() {
        //获取到容器
        ApplicationContext ioc =
                new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");

        //获取JdbcTemplate对象
        JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);

        //1.确定API query
        //public  List query(String sql, RowMapper rowMapper, Object... args)
        //2.准备参数
        String sql = "SELECT id AS monsterId, `name`, skill FROM monster WHERE id >= ?";//这个?填进入也可以
        RowMapper<Monster> rowMapper = new BeanPropertyRowMapper<>(Monster.class);
        //3.调用
        List<Monster> monsterList = jdbcTemplate.query(sql, rowMapper, 200);
        //输出
        for (Monster monster : monsterList) {
            System.out.println("monster=" + monster);
        }
    }
}

测试结果

monster=Monster{monsterId='200', name='红孩儿', skill='三昧真火'}
monster=Monster{monsterId='300', name='铁扇公主', skill='美人计'}
monster=Monster{monsterId='400', name='陆小千', skill='魔幻手机'}
monster=Monster{monsterId='500', name='金角大王', skill='紫金红葫芦'}
monster=Monster{monsterId='600', name='鼠鼠', skill='偷吃粮食'}
monster=Monster{monsterId='700', name='猫猫', skill='抓老鼠'}

Spring系列六:JdbcTemplate_第14张图片

返回单行单列

Spring系列六:JdbcTemplate_第15张图片

public class JdbcTemplateTest {
    /**
     * 查询返回结果只有一行一列的值
     */
    @Test
    public void selectScalarByJdbcTemplate() {
        //获取到容器
        ApplicationContext ioc =
                new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");

        //获取JdbcTemplate对象
        JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);

        //1.确定API query -> queryObject
        //public  T queryForObject(String sql, Class requiredType, @Nullable Object... args)
        //2.准备参数
        String sql = "SELECT `name` FROM monster WHERE id = 100";
        //Class requiredType 表示你返回的单行单列的数据类型
        //3.调用
        String name = jdbcTemplate.queryForObject(sql, String.class);
        //输出
        System.out.println("name=" + name);
        System.out.println("ok~");
    }
}

具名参数

配置JdbcTemplate_ioc.xml, 使用到NamedParameterJdbcTemplate


<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.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    
    <context:property-placeholder location="classpath:jdbc.properties"/>
    
    <bean class="com.mchange.v2.c3p0.ComboPooledDataSource" id="dataSource">
        
        <property name="user" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.pwd}"/>
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
    bean>

    
    
    <bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
        
        <property name="dataSource" ref="dataSource"/>
    bean>

    
    <bean class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate" id="namedParameterJdbcTemplate">
        
        <constructor-arg name="dataSource" ref="dataSource"/>
    bean>
beans>

Spring系列六:JdbcTemplate_第16张图片

public class JdbcTemplateTest {
    /**
     * 使用Map传入具名参数完成操作, 比如添加
     */
    @Test
    public void testDataByNamedParameterJdbcTemplate() {
        //获取到容器
        ApplicationContext ioc =
                new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");

        //得到NamedParameterJdbcTemplate bean
        NamedParameterJdbcTemplate namedParameterJdbcTemplate = ioc.getBean(NamedParameterJdbcTemplate.class);

        //1.确定API update
        //public int update(String sql, Map paramMap)

        //2.准备参数 [:my_id, :name, :skill] 要求按照规定的名字来设置参数
        String sql = "insert into monster values(:id, :name, :skill)";
        Map<String, Object> paramMap = new HashMap<>();
        //给paramMap填写数据
        paramMap.put("id", 800);
        paramMap.put("name", "二郎神");
        paramMap.put("skill", "哮天犬");
        //3.调用
        int affected = namedParameterJdbcTemplate.update(sql, paramMap);
        //输出
        System.out.println("add ok affected=" + affected);
    }
}

sqlparametersource

Spring系列六:JdbcTemplate_第17张图片
Spring系列六:JdbcTemplate_第18张图片

public class JdbcTemplateTest {
    /**
     * 使用sqlparamtersource 来封装具名参数, 还是添加一个Monster
     */
    @Test
    public void operDataBySqlparametersource() {
        //获取到容器
        ApplicationContext ioc =
                new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");

        //得到NamedParameterJdbcTemplate bean
        NamedParameterJdbcTemplate namedParameterJdbcTemplate = ioc.getBean(NamedParameterJdbcTemplate.class);

        //1.确定API query
        //public int update(String sql, SqlParameterSource paramSource)
        //public BeanPropertySqlParameterSource(Object object)
        //2.准备参数
        String sql = "insert into monster values(:id, :name, :skill)";
        Monster monster = new Monster(900, "妲己", "魅惑");
        SqlParameterSource sqlParameterSource = new BeanPropertySqlParameterSource(monster);
        //3.调用
        int affected = namedParameterJdbcTemplate.update(sql, sqlParameterSource);
        //输出
        System.out.println("add ok affected=" + affected);
    }
}

结果报错 No value supplied for the SQL parameter 'id': Invalid property 'id' of bean class [com.zzw.spring.bean.Monster]: Bean property 'id' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?

修改代码

String sql = "insert into monster values(:monterId, :name, :skill)";

DAO使用jdbctemplate

com.zzw.spring.jdbctemplate.dao包下新建MonsterDao

@Repository //将MonsterDao注入到spring容器
public class MonsterDao {

    //注入一个属性
    @Resource
    private JdbcTemplate jdbcTemplate;

    //完成保存任务
    public void save(Monster monster) {
        //组织SQL
        String sql = "insert into monster values(?, ?, ?)";
        int affteced =
                jdbcTemplate.update(sql, monster.getMonsterId(), monster.getName(), monster.getSkill());
        System.out.println("affected=" + affteced);
    }
}

JdbcTemplate_ioc.xml


<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.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    
    <context:component-scan base-package="com.zzw.spring.jdbctemplate.dao"/>

    
    <context:property-placeholder location="classpath:jdbc.properties"/>
    
    <bean class="com.mchange.v2.c3p0.ComboPooledDataSource" id="dataSource">
        
        <property name="user" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.pwd}"/>
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
    bean>

    
    
    <bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
        
        <property name="dataSource" ref="dataSource"/>
    bean>

    
    
beans>

测试

public class JdbcTemplateTest {
    //测试MonsterDao是否生效
    @Test
    public void monsterDaoSave() {
        //获取到容器
        ApplicationContext ioc =
                new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");

        MonsterDao monsterDao = ioc.getBean(MonsterDao.class);

        monsterDao.save(new Monster(1000, "女娲", "女娲补天"));

        System.out.println("save ok~");
    }
}

你可能感兴趣的:(Spring5,spring,java,后端)