day14-JdbcTemplate-01

2023-01-31 06:00:42

JdbcTemplate-01

看一個實際需求:

如果希望使用spring框架做專案,Spring框架如何處理對資料庫的操作呢?

  • 方案一:使用之前的JdbcUtils類

  • 方案二:spring提供了一個運算元據庫(表)的功能強大的類JdbcTemplate。我們可以通過ioc容器來設定一個JdbcTemplate物件,使用它來完成對資料庫表的各種操作。

1.基本介紹

JdbcTemplate APIs:下載的檔案-spring-5.3.8-dist\spring-framework-5.3.8\docs\javadoc-api\index.html

  1. 通過Spring可以設定資料來源,從而完成對資料表的操作
  2. JdbcTemplate 是 spring 提供的存取資料庫的技術。可以將 JDBC 的常用操作封裝為模板方法。
image-20230130183802247

2.使用範例

需求說明:使用 Spring 的方式來完成 JdbcTemplate 設定和使用

一、搭建環境:

  1. 引入JdbcTemplate 需要的jar包(Spring5)

    image-20230130182521048
  2. 建立資料庫spring和表monster

-- 建立資料庫
CREATE DATABASE spring;
USE spring;
-- 建立表monster
CREATE TABLE monster(
id INT 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,'蜘蛛怪','吐絲');
image-20230130184434097

二、設定DataSource

  1. 建立組態檔src/jdbc.properties(key值隨意)

在spring的ioc容器中,可以通過屬性檔案給bean注入值

jdbc.user=root
jdbc.pwd=123456
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring
  1. 建立容器組態檔src/JdbcTemplate_ioc.xml
<!--引入外部的屬性檔案-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--設定資料來源物件-DataSource-->
<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>
  1. 測試連線
@Test
public void testDatasourceByJdbcTemplate() throws SQLException {
    //獲取容器
    ApplicationContext ioc = 
        new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");
    //因為 ComboPooledDataSource實現了 DataSource介面,這裡使用介面型別來獲取物件
    DataSource dataSource = ioc.getBean(DataSource.class);
    Connection connection = dataSource.getConnection();
    System.out.println("獲取到連線connection=" + connection);
    connection.close();
}

成功連線:

image-20230130194736188
  1. 設定 JdbcTemplate_ioc.xml,將資料來源分配給 JdbcTemplate bean物件
<!--設定JdbcTemplate物件-->
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
    <!--給JdbcTemplate物件設定DataSource屬性-->
    <property name="dataSource" ref="dataSource"/>
</bean>

2.1新增資料

@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.新增方式 2(推薦)
    String sql2 = "insert into monster values(?,?,?)";
    //返回的 int型別 表示執行後表受影響的記錄數
    int affected = jdbcTemplate.update(sql2, 500, "牛魔王", "芭蕉扇");
    System.out.println("add ok affected = " + affected);
}

新增成功:

image-20230130200640803 image-20230130201116969

2.2修改資料

//測試通過JdbcTemplate物件完成修改資料
@Test
public void updateDataByJdbcTemplate() {
    //獲取容器
    ApplicationContext ioc =
            new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");
    
    //獲取JdbcTemplate物件
    JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);
    
    String sql = "update monster set skill=? where id=?";
    int affected = jdbcTemplate.update(sql, "美人計", 300);
    System.out.println("update is ok, affected = " + affected);
}

修改成功:

image-20230130201656523 image-20230130201723618

2.3批次處理

對於某個類,如果有很多API,使用的步驟:

1.先確定API名字 2.根據API提供的引數,組織引數 3.根據API可以推測類似的用法和功能

//批次新增兩個 monster
@Test
public void addBatchDataByJdbcTemplate() {
    //獲取容器
    ApplicationContext ioc =
            new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");

    //獲取JdbcTemplate物件
    JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);

    //1.準備引數
    String sql = "insert into monster values(?,?,?)";
    List<Object[]> batchArgs = new ArrayList<>();
    batchArgs.add(new Object[]{600, "白蛇", "翻江倒海"});
    batchArgs.add(new Object[]{700, "青蛇", "竹葉青"});

    //2.呼叫
    //int[] batchUpdate(String sql, List<Object[]> batchArgs);
    //說明:返回結果為int陣列,每個元素對應上面的sql語句對錶的影響記錄數
    int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);

    //輸出
    for (int anInt : ints) {
        System.out.println("anInt=" + anInt);
    }
    System.out.println("batch add is ok..");
}

批次處理結果:

image-20230130203736793 image-20230130203812283

2.4查詢

實體類 Monster.java

package com.li.bean;

/**
 * @author 李
 * @version 1.0
 * Javabean / Entity
 */
public class Monster {
    private Integer monsterId;
    private String name;
    private String skill;

    //無參構造器一定要有,spring底層反射建立物件時需要使用
    public Monster() {
    }

    //全參構造器
    public Monster(Integer monsterId, String name, String skill) {
        this.monsterId = monsterId;
        this.name = name;
        this.skill = skill;
    }

    public Integer getMonsterId() {
        return monsterId;
    }

    public void setMonsterId(Integer monsterId) {
        this.monsterId = monsterId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSkill() {
        return skill;
    }

    public void setSkill(String skill) {
        this.skill = skill;
    }

    @Override
    public String toString() {
        return "Monster{" +
                "monsterId=" + monsterId +
                ", name='" + name + '\'' +
                ", skill='" + skill + '\'' +
                '}';
    }
}

2.4.1查詢單行多列

查詢 id=500 的 monster 並封裝到 Monster 實體物件

//查詢 id=100的 monster並封裝到 Monster實體物件
@Test
public void selectDataByJdbcTemplate() {
    //獲取容器
    ApplicationContext ioc =
            new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");
    //獲取JdbcTemplate物件
    JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);

    //1.確定API
    //<T> T queryForObject(String sql, RowMapper<T> rowMapper, @Nullable Object... args)
    
    //2.準備引數
    //注意:封裝物件時,如果查詢返回的欄位名和實體物件的屬性名不一致會出現問題,最好使用別名!
    String sql = "SELECT id AS monsterId , NAME, skill FROM monster WHERE id=?";
    //使用RowMapper介面來對返回的資料,進行一個封裝(底層是反射->setter)
    RowMapper<Monster> rowMapper = new BeanPropertyRowMapper<>(Monster.class);
    
    //3.呼叫
    Monster monster = jdbcTemplate.queryForObject(sql, rowMapper, 500);
    System.out.println("monster=" + monster);
}

查詢結果:

image-20230130210708174

2.4.2查詢多行多列

查詢 id>=200 的 monster,並封裝到 Monster 實體物件

//查詢 id>=200的 monster並封裝到 Monster實體物件
@Test
public void selectMulDataByJdbcTemplate() {
    //獲取容器
    ApplicationContext ioc =
            new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");
    //獲取JdbcTemplate物件
    JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);

    //1.確定API
    //public <T> T query(String sql, ResultSetExtractor<T> rse, @Nullable Object... args)
    //2.組織引數
    String sql = "SELECT id AS monsterId , NAME, skill FROM monster WHERE id>= ?";
    BeanPropertyRowMapper<Monster> rowMapper = new BeanPropertyRowMapper<>(Monster.class);

    List<Monster> query = jdbcTemplate.query(sql, rowMapper, 200);
    for (Monster monster : query) {
        System.out.println("monster=" + monster);
    }
}

查詢結果:

image-20230130211933967

2.4.3查詢單行單列

查詢返回結果只有單行單列的值,比如查詢表中的總記錄數,或者查詢 id=200 的 name 欄位的值

//查詢 id>=200的 monster並封裝到 Monster實體物件
@Test
public void selectScalarByJdbcTemplate() {
    //獲取容器
    ApplicationContext ioc =
            new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");
    //獲取JdbcTemplate物件
    JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);

    //1.確定API
    // public <T> T queryForObject(String sql, Class<T> requiredType, @Nullable Object... args)
    //requiredType 表示返回的單行單列的 值的 資料型別

    //2.組織引數
    String sql = "SELECT NAME FROM monster WHERE id=?";
    String sql2 = "SELECT COUNT(*) FROM monster";
    //3.呼叫
    String name = jdbcTemplate.queryForObject(sql, String.class, 200);
    Integer count = jdbcTemplate.queryForObject(sql2, Integer.class);
    System.out.println("id=200 的 name = " + name);
    System.out.println("monster表的總記錄數 = " + count);
}

查詢結果:

image-20230130213520356

2.5具名引數

  • 在 JDBC用法中,SQL引數是用預留位置 ? 表示,並且受到位置的限制。

    定位引數的問題在於,一旦引數的位置發生變化,必須改變引數的繫結,在Spring JDBC中,繫結SQL引數的另一種選擇是使用具名引數 (named parameter),SQL具名引數是按照名稱繫結,而不是位置繫結。

  • 什麼是具名引數?

    具名引數:SQL 按名稱(以冒號開頭)而不是按位元置進行指定。具名引數更易於維護, 也提升了可讀性。具名引數由框架類在執行時用預留位置取代。