【Mysql6】jdbc


1.jdbcTemplate的execute和update方法

在这里插入图片描述

package com.itheima01.template;
import com.itheima.utils.JdbcUtil;
import org.junit.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
/*
*  JdbcTemplate:是spring的框架的一部分,spring框架是工具箱。作用: 简化jdbc代码编写
*      #使用:1. 数据库的操作
*               1. DDL : create/drop/alter/truncate
*               2. DML : insert/delete/update
*               3. DQL : select
*               4. DCL : transaction/权限
*            2. 核心API
*               核心类: JdbcTemplate。构造方法:JdbcTemplate(DataSource ds)
*               核心方法: A. void execute : 理论上可以执行任意sql,适合执行DDL,因为void无返回值
*                        B. int update  : 适合执行DML
*                        C. 多种多样 query : 适合执行DQL,返回多种多样
*/
public class TemplateDemo01 {
    
    
    @Test
    public void execute(){
    
    
        String sql = "create table student(id int primary key auto_increment,name varchar(20),age int)";
        DataSource ds = JdbcUtil.getDs(); //拿到连接池
        JdbcTemplate template = new JdbcTemplate(ds);
        
        template.execute(sql); //无返回值
        System.out.println("执行结束");
    }
    
    @Test
    public void update01(){
    
    
        String sql = "insert into student values(null,?,?),(null,?,?)";
        JdbcTemplate template = new JdbcTemplate(JdbcUtil.getDs());
        /*
        * int update(String sql, Object... args)
        *   Object... args:
        *       1. Object原因是参数类型是不确定的 -> Object
        *       2. ... 原因是参数个数不确定
        *   返回值: 被影响的行数
        */
        int count = template.update(sql, "zs", 18, "ls", 19);
        System.out.println(count); //2
    }
    
    @Test
    public void update02(){
    
    
        String sql = "update student set age = ? where id = ?";
        JdbcTemplate template = new JdbcTemplate(JdbcUtil.getDs());
        
        Object[] args = {
    
    99,1}; //可变参数本质是数组
        int update = template.update(sql, args); 
        System.out.println(update);
    }
}

2.queryForXX方法

一行map是一个对象,query方法用的是多个对象这个。
在这里插入图片描述

package com.itheima01.template;
import com.itheima.utils.JdbcUtil;
import org.junit.Test;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.List;
import java.util.Map;
import java.util.Set;
/*
*   C. 多种多样 query : 适合执行DQL
*       1. queryForXX : XX表示返回值类型
*           a. queryForObject
*           b. queryForMap
*           c. queryForList
* 
*       2. query(RowMapper 行映射器)
*/
public class TemplateDemo02 {
    
    
    JdbcTemplate template = new JdbcTemplate(JdbcUtil.getDs());
    @Test
    public void queryForObject01(){
    
    
        String sql = "select count(*) from student";
        /*
        * <T> T queryForObject(String sql, Class<T> requiredType)
        *     requiredType : 返回值类型 -> Class对象
        *
        *     EmptyResultDataAccessException : 空结果异常
        *       查询不到任何数据,会报这个错
        */
        Integer count = template.queryForObject(sql, Integer.class);
        System.out.println(count);
    }
    
    @Test
    public void queryForObject02(){
    
    
        String sql = "select name from student where id = ?";
        String s = null;
        try {
    
    
            s = template.queryForObject(sql, String.class,3); //3传入上面?
        } catch (DataAccessException e) {
    
    
            e.printStackTrace();
            System.out.println("查询不到任何结果");
        }
        System.out.println(s);
    }
   
    @Test
    public void queryForMap(){
    
    
        String sql = "select * from student where id = ?";
        Map<String, Object> map = template.queryForMap(sql, 1);
//        System.out.println(map);  //{id=1,name=zs,age=99}
        Set<Map.Entry<String, Object>> entrySet = map.entrySet();
        for (Map.Entry<String, Object> entry : entrySet) {
    
    
            String key = entry.getKey();
            Object value = entry.getValue();
            System.out.println(key + "=" + value); //竖着打印id=1 name=zs age=99
        }
    }

    @Test
    public void queryForList(){
    
    
        String sql = "select * from student";
        List<Map<String, Object>> list = template.queryForList(sql);        
        for (Map<String, Object> map : list) {
    
    
            System.out.println(map); //{id=1,name=zs,age=99} 换行 {id=2,name=ls,age=19}
        }
    }
}

3.query方法

package com.itheima01.template;
/*
*   JavaBean三要素:
*       1. private属性,属性名和表中字段名是一致的!!! 都是引用类型(因为数据库中空为null,不是0)
*       2. public get set方法
*       3. public 空参构造
*/
public class Student {
    
    
    private Integer id;
    private String name;
    private Integer age;
    @Override
    public String toString() {
    
    
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    public Integer getId() {
    
    
        return id;
    }
    public void setId(Integer id) {
    
    
        this.id = id;
    }
    public String getName() {
    
    
        return name;
    }
    public void setName(String name) {
    
    
        this.name = name;
    }
    public Integer getAge() {
    
    
        return age;
    }
    public void setAge(Integer age) {
    
    
        this.age = age;
    }
}
package com.itheima01.template;
import com.itheima.utils.JdbcUtil;
import org.junit.Test;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

public class TemplateDemo03 {
    
    
    JdbcTemplate template = new JdbcTemplate(JdbcUtil.getDs());
    @Test
    public void query01(){
    
    
        String sql = "select * from student";        
        /*
        * List<T> query(String sql, RowMapper<T> rm)
        *  RowMapper : 行映射器 (接口)。方法参数中有接口类型, 那么调用的时候必须传入接口的实现类对象
        */
        RowMapper<Student> rowMapper = new RowMapper<Student>() {
    
    
            /*
            *  如下Student mapRow(ResultSet resultSet, int i)
            *       映射行 : resultSet 转换为 Student
            *       1. resultSet : 结果集(每行)
            *       2. i : 当前的行索引(没什么用)
            */
            @Override
            public Student mapRow(ResultSet resultSet, int i) throws SQLException {
    
    
                String name = resultSet.getString("name");
                int id = resultSet.getInt("id");
                int age = resultSet.getInt("age");
                Student s = new Student();
                s.setId(id);
                s.setName(name);
                s.setAge(age);
                System.out.println(i);
                return s;
            }
        };                
 //RowMapper行映射器 像 动态代理中 InvocationHandler调用处理器,mapRow方法像invoke方法
        List<Student> list = template.query(sql, rowMapper);
        System.out.println(list); 
        //打印出[Student{id=1,name='zs',age=99},Student{id=2,name='ls',age=19}]
    }

    @Test
    public void query02(){
    
    
        String sql = "select * from student";
        /*
            BeanPropertyRowMapper: 类
                1. RowMapper接口的实现类
                2. BeanPropertyRowMapper(xx.class); 返回值的泛型
        */
        /*
        * BeanPropertyRowMapper (底层反射),思路如下:
        *    1. 实现RowMapper接口
        *    2. 重写mapRow方法 : 每行ResultSet -> javaBean
        *       1. 获取结果集中的数据
        *           知道结果集有哪些字段 -> 结果集元数据
        *           值 = resultSet.get(字段);
        *           id值 = id
        * 
        *       2. 设置到javabean中去 (需要传参: Student.class)
        *           clazz = Student.class //获取类
        *           Student s = clazz.newInstance(); // javabean规范: 默认调用空参构造	
        *			// Student s = new Student(); //等同于上面两行
        *	      
        *			//并不知道Student对象有哪些方法,通过反射如下
        *             setIdMethod = clazz.getMethod("setId",int.class); 
        *           //怎么知道Student对象中有setId方法呢?
        *			//因为javabean规范 : 必有set方法。额外要求:set+名字(必须要和表中的字段名一致)
        *             setIdMethod.invoke(s,id值);
        */
        RowMapper<Student> rowMapper = new BeanPropertyRowMapper<>(Student.class);
        List<Student> list = template.query(sql, rowMapper);
        System.out.println(list); //打印出同query01()
    }
}

4.源码和测试

package com.itheima03.source;
import com.itheima.utils.JdbcUtil;
import com.itheima01.template.Student;
import org.junit.Test;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/*
*  代码封装:
*       1. 先把完整的代码写出来
*       2. 进行抽取(定义方法, 参数, 返回值)
*    扩展性:
*       1. 不变的内容留在框架里
*       2. 变化的内容变成参数
*/
public class SrcDemo {
    
    
    @Test
    public void updateSrc() throws SQLException {
    
     //如下完整代码写出来
        String sql = "insert into student values(null,?,?)";
        DataSource ds = JdbcUtil.getDs(); //连接池
        Connection conn = ds.getConnection(); //拿到连接
        PreparedStatement pstm = conn.prepareStatement(sql); //预编译
        pstm.setString(1,"ww");
        pstm.setString(2,"20");
        int count = pstm.executeUpdate();
        System.out.println(count);
    }   
      
    @Test
    public void update01() throws SQLException {
    
     //测试MyTemplate.java中封装的update()。这里面代码和本文第一章update01()一样。
        String sql = "insert into student values(null,?,?)";
        MyTemplate template = new MyTemplate(JdbcUtil.getDs());
        int count = template.update(sql, "ml", 33);
        System.out.println(count);
    }
    
    @Test
    public void update02() throws SQLException {
    
     //测试MyTemplate.java中封装的update()
        String sql = "insert into student values(null,?,?)";
        MyTemplate template = new MyTemplate(JdbcUtil.getDs());
        int count = template.update(sql);  //没传参,不合法,所以需要框架封装者做健壮性校验
        System.out.println(count);
    }

//11111111111111111111111111111111111111111111111111111111111111111111111111111    
    @Test
    public void query01() throws SQLException {
    
     //如下完整代码写出来,query源码
        String sql = "select * from student where id > ?";
        DataSource ds = JdbcUtil.getDs();
        Connection conn = ds.getConnection();
        PreparedStatement pstm = conn.prepareStatement(sql);
        pstm.setInt(1,2); //1指第一个?,2对?赋值
        ResultSet resultSet = pstm.executeQuery();
        
        // resultSet -> List<Student>
        List<Student> list = new ArrayList<>();
        while(resultSet.next()){
    
    
            int id = resultSet.getInt("id");
            int age = resultSet.getInt("age");
            String name = resultSet.getString("name");
            Student s = new Student();
            s.setId(id);
            s.setName(name);
            s.setAge(age);
            list.add(s);
        }
        System.out.println(list);  
        //[Student{id=3,name='ww',age=20},Student{id=4,name='ml',age=33}]
    }
    
    @Test
    public void query02() throws SQLException {
    
      //测试MyTemplate.java中封装的query()
        String sql = "select * from student where id > ?";
        MyTemplate02 template = new MyTemplate02(JdbcUtil.getDs());
        MyRowMapper<Student> rm = new MyRowMapper() {
    
    
            @Override
            public Student mapRow(ResultSet resultSet) throws SQLException {
    
     //父类方法抛出编译异常,子类才能抛。
                int id = resultSet.getInt("id");
                int age = resultSet.getInt("age");
                String name = resultSet.getString("name");
                Student s = new Student();
                s.setId(id);
                s.setName(name);
                s.setAge(age);
                return s;
            }
        };
        List<Student> list = template.query(sql, rm, 2);
        System.out.println(list);  
        //打印同上[Student{id=3,name='ww',age=20},Student{id=4,name='ml',age=33}]
    }
}

如下右边rm是父类引用,rm.mapRow执行子类重写方法。左边resultSet已由右边遍历结束了。
在这里插入图片描述

5.封装

package com.itheima03.source;
import com.itheima.utils.JdbcUtil;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.SQLException;
   
public class MyTemplate {
    
     //框架设计者即封装源码
    DataSource ds; //不同的方法,同一个ds连接池
    public MyTemplate(DataSource ds){
    
      //通过构造传入ds
        this.ds = ds;
    }
    /*
    *   代码健壮性: 调用此方法传入的参数个数必须和sql的?数量一致
    *       1. 参数的个数:args.length
    *       2. sql的?的数量:如下a或b都可以
    *           a. 截取字符串
    *           b. 元数据 metadata !!!
    *               brand(元数据) = 香奈儿 (数据)
    *               字段(元数据) = 对应的值(数据)
    */
    public int update(String sql,Object... args) throws SQLException {
    
     //封装updateSrc()
        // String sql = "insert into student values(null,?,?)"; //这句会变化,用参数传入
        // DataSource ds = JdbcUtil.getDs(); //连接池  //不要和JdbcUtil耦合,所以DataSource ds放到成员位置,通过构造传入。
        // pstm.setString(1,"ww"); //也不知道sql占位多少,抽出去。换成下面 for (int i = 0; i < args.length; i++) {pstm.setObject(i+1,args[i]);}  //都是从1往后排,没有0,(null,?,?)不是数组
         
        Connection conn = ds.getConnection(); //拿到连接
        PreparedStatement pstm = conn.prepareStatement(sql); //预编译
        
        //获取参数元数据 (name=?,age=?)  //下面5行健壮性校验,不让框架使用者乱用
        ParameterMetaData parameterMetaData = pstm.getParameterMetaData();
        int parameterCount = parameterMetaData.getParameterCount();
        if(args.length != parameterCount){
    
    
            throw new StupidBirdException("你个傻鸟,参数个数和?个数对应不上~~");
        }
        
        for (int i = 0; i < args.length; i++) {
    
    
            pstm.setObject(i+1,args[i]);
        }
        int count = pstm.executeUpdate(); //这里要连接数据库报错,上面健壮性校验编译时就报错,不用连数据库
        pstm.close(); 
        conn.close();
        return count;
    }
    
    public void execute(){
    
    
    }
}
class StupidBirdException extends SQLException{
    
     //自定义异常
    public StupidBirdException(String msg){
    
    
        super(msg);
    }
}

如下是query方法封装

package com.itheima03.source;
import com.itheima.utils.JdbcUtil;
import com.itheima01.template.Student;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class MyTemplate02 {
    
    
    DataSource ds;
    public MyTemplate02(DataSource ds){
    
    
        this.ds = ds;
    }
    
    public <T>List<T> query(String sql,MyRowMapper<T> rm,Object... args) throws SQLException {
    
    
     //往参数列表设置接口方式,强迫用户重写抽象方法
//        String sql = "select * from student where id > ?"; // 变量 -> 参数
//        DataSource ds = JdbcUtil.getDs();
        Connection conn = ds.getConnection();
        PreparedStatement pstm = conn.prepareStatement(sql);
//        pstm.setInt(1,2);
 
        int parameterCount = pstm.getParameterMetaData().getParameterCount();
        if(parameterCount != args.length){
    
     //健壮性校验
            throw new IllegalArgumentException("傻鸟~~");
        }
        
        for (int i = 0; i < args.length; i++) {
    
     //快捷键 args.fori
            pstm.setObject(i+1,args[i]);
        }
        
        ResultSet resultSet = pstm.executeQuery();
        List<T> list = new ArrayList<>();
        while(resultSet.next()){
    
     //一次遍历一行,将这一行映射为java bean对象,所以叫mapRow
            /*
            * 如下代码会动态变化的(sql不同,结果集就会不同)。希望由用户自己来封装javaBean对象
            *   1. 之前: 变量动态 -> 参数(全局,局部)
            *   2. 现在: 如何将一段代码动态化:一段代码 提取成 方法 
            *  (在java中,方法不能作为参数,参数只能是基本类型或引用类型[类,接口,枚举,注解])
            * 
            *  如下我可以提供结果集给你,你要给我数据设置好的javaBean对象
            *  Student 方法名(resultSet); 封装没办法写方法体,需要用户自己写 -> 抽象方法 
            *  所以 方法名mapRow 要放在 接口MyRowMapper 里
            */
          /*  int id = resultSet.getInt("id");
            int age = resultSet.getInt("age");
            String name = resultSet.getString("name");
            Student s = new Student();
            s.setId(id);
            s.setName(name);
            s.setAge(age);*/
            T s = rm.mapRow(resultSet); //给你resultSet,还我T类
            list.add(s);
        }
        pstm.close();
        conn.close();
       return list;
    }
}
interface MyRowMapper<T>{
    
    
    T mapRow(ResultSet resultSet) throws SQLException;
}

B站/知乎/微信公众号:码农编程录
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43435675/article/details/109158899