【database1】mysql:DDL/DML/DQL,外键约束/多表/子查询,事务/连接池

文章目录

  • 1.mysql安装:存储:集合(内存:临时),IO流(硬盘:持久化)
    • 1.1 服务端:双击mysql-installer-community-5.6.22.0.msi
    • 1.2 客户端:命令行输入mysql -u...实际是如下安装路径的bin文件夹的mysql.exe
  • 2.DDL/DML:char不用动态变化,效率高
  • 3.DQL:select(相当于System.out)第一个但在倒数第二执行
  • 4.约束和自增长:字段约束(字段的赋值规范)/主键约束(唯一非空且一张表只有一个主键)
  • 5.单表缺点和外键约束:多从外 引出
  • 6.三种多表关系:中间表两外键:一对一(简历),一对多(员工,部门),多对多(学生,课表)
  • 7.多表查询:表..join表on
    • 7.1 外连接:左外=左表+内连接
  • 8.子查询:优先于主查询产生结果
  • 9.事务:一组操作,要么同时成功,要么同时失败
  • 10.四个接口:左java.sql包下的DCSR,右com.mysql.jdbc.Driver
  • 11.释放资源:finally,工具类封装
  • 12.JDBC事务操作:conn.setAutoCommit(false)
  • 13.登陆案例预编译改造:PreparedStatement,setString,executeQuery
  • 14.c3p0连接池:jdbc2.0才引进连接池,不是线程池(连接池的技术标准就是DataSource替代DriverManager)
  • 15.druid连接池:自动ds.set
  • 16.execute/update方法:template =
  • 17.queryForXX/query方法:Map.Entry < String, Object > ,Map < String, Object > 两个数据类型


1.mysql安装:存储:集合(内存:临时),IO流(硬盘:持久化)

1.1 服务端:双击mysql-installer-community-5.6.22.0.msi

mysql安装包:链接:https://pan.baidu.com/s/18Ctus6BLVrECZP0W-QKtfw 提取码:94s9。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
上面next,execute安装后,下面开始配置。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.2 客户端:命令行输入mysql -u…实际是如下安装路径的bin文件夹的mysql.exe

命令行java -version要配环境变量,看mysql有没有运行,只能从任务管理器看有没有mysql的进程。
在这里插入图片描述
win下cmd输入:完整版没有括号:mysql -h(host) 127.0.0.1 -P(port) 3306 -u(username) root -p(password)。简略版:mysql -u root -p。
在这里插入图片描述
可视化工具navicat链接:https://pan.baidu.com/s/11qAEA7yEGSIz6J9GIC_S6A 提取码:1w9n。navicat免安装链接:https://pan.baidu.com/s/1zanhYyyNsUXajI-czfW7KA 提取码:om5g。
在这里插入图片描述

2.DDL/DML:char不用动态变化,效率高

如下中间蓝框里一个数据库相当于一个excel表,紫色框里一个table相当于excel表里的一个sheet。use数据库相当于双击打开excel表格,select查看函数返回值,desc全称description,like复制表结构,change 旧字段 新字段 新类型
在这里插入图片描述
数据库名字不建议修改,用数据库备份改名(新建一个数据库,把原数据库数据复制过来)。mysql中utf-8中-无法识别,用utf8。ISO-8859-1用latin1。
在这里插入图片描述
注意(),逗号,分号。
在这里插入图片描述
如下数(整小)日字,oracle两个不同:number包含整小,varchar2。
在这里插入图片描述
选用timestamp而不用datetime,因为datetime不会自动设置时间。
在这里插入图片描述
int(11)默认11位不用写出来,2147483647即21亿10位,如果有负数还有最前面一位是符号位,所以一共11位
在这里插入图片描述
如下是表记录,select非常多,删除只是记录,表结构还在。
在这里插入图片描述
在这里插入图片描述
DDL后面不需要加from等词。
在这里插入图片描述
如下单引号可加可不加。
在这里插入图片描述
在这里插入图片描述
如下要写两个add。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.DQL:select(相当于System.out)第一个但在倒数第二执行

如下3中第一排序字段相同的里面再进行第二排序。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如下查询id是1或3或5的学生。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
d低下降,只要有数字都比null大。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如下有英语成绩有6个,不能代表总人数,缺考没算入。
在这里插入图片描述
在这里插入图片描述
select后的第一个字段要和group by后同。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如下是select语句执行顺序,红字书写顺序必须这样。
在这里插入图片描述
sql只有一种情况报错:语法写错。如下索引越界不会报错。
在这里插入图片描述
page和count是前端传来的两个参数,count不用变。
在这里插入图片描述
数量(count(*))降序只要一个(limit 1)。
在这里插入图片描述
如下将db3数据库整个连数据备份,本质create,insert。记住mysqldump和source。
在这里插入图片描述
在这里插入图片描述

4.约束和自增长:字段约束(字段的赋值规范)/主键约束(唯一非空且一张表只有一个主键)

在这里插入图片描述
在这里插入图片描述
如下验证主键唯一和非空,如下两个框都报错。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如下的Null列表示是否允许为空。
在这里插入图片描述

5.单表缺点和外键约束:多从外 引出

多表是外键约束的前提,外键约束解决下面多表的2个问题,add…多了一条线。alter table emploee drop foreign key fk_001。
在这里插入图片描述
如上是在已有表添加外键,如下建表就添加(开发中常用)。
在这里插入图片描述
在这里插入图片描述
如果要删除department表的id为001即整个研发部门,需要先在employee表中删除id=001的很多记录,很麻烦。现在想要删除department的001部门时employee为001的行也一起删了,所以用外键级联操作,如下create table …中省略同上。
在这里插入图片描述

6.三种多表关系:中间表两外键:一对一(简历),一对多(员工,部门),多对多(学生,课表)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

7.多表查询:表…join表on

CREATE DATABASE day03;
USE day03;
-- 创建部门表
CREATE TABLE dept (
  id INT PRIMARY KEY AUTO_INCREMENT,
  NAME VARCHAR(20)
);
INSERT INTO dept (NAME) VALUES ('开发部'),('市场部'),('财务部');
-- 创建员工表
CREATE TABLE emp ( 
  id INT PRIMARY KEY AUTO_INCREMENT,
  NAME VARCHAR(10),
  gender CHAR(1),   -- 性别
  salary DOUBLE,   -- 工资
  join_date DATE,  -- 入职日期
  dept_id INT
);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('孙悟空','男',7200,'2013-02-24',1);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('猪八戒','男',3600,'2010-12-02',2);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('唐僧','男',9000,'2008-08-08',2);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('白骨精','女',5000,'2015-10-07',3);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('蜘蛛精','女',4500,'2011-03-14',1);

如下要查出有用的记录需要emp.dept_id(emp外键)=dept.id(dept主键)。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
因为select * ,所以将两个橙色横框拼接起来,棕色框。
在这里插入图片描述

7.1 外连接:左外=左表+内连接

如下注意记住左表不动。
在这里插入图片描述
如下第一个内连接没有销售部(销售部没有和员工表任何数据相交),第二个有销售部。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
union all不去重,左外连接+右外连接。
在这里插入图片描述
在这里插入图片描述

8.子查询:优先于主查询产生结果

在这里插入图片描述
如下执行两句sql,要连接两次数据库,子查询一般要写在()里。
在这里插入图片描述
在这里插入图片描述
如下1,2是dept_id,可以把in换成 = any
在这里插入图片描述
如下第一行和第二行效果相同。
在这里插入图片描述
如下两个select等价。
在这里插入图片描述
如下还是写上面的题目,如果用内连接,沙僧会没有,左外或右外连接都可以。
在这里插入图片描述
如下将上面的id1列去除(即将dept表的id列去除不显示)。
在这里插入图片描述
on比where先执行。
在这里插入图片描述
在这里插入图片描述

-- 11111111111111111111111111111111111111111111111111111111111111111部门表
CREATE TABLE dept (
  id INT PRIMARY KEY PRIMARY KEY, -- 部门id
  dname VARCHAR(50), -- 部门名称
  loc VARCHAR(50) -- 部门位置
);
-- 添加4个部门
INSERT INTO dept(id,dname,loc) VALUES 
(10,'教研部','北京'),
(20,'学工部','上海'),
(30,'销售部','广州'),
(40,'财务部','深圳');

-- 1111111111111111111111111111111111111111111111111111111职务表,职务名称,职务描述
CREATE TABLE job (
  id INT PRIMARY KEY,
  jname VARCHAR(20),
  description VARCHAR(50)
);
-- 添加4个职务
INSERT INTO job (id, jname, description) VALUES
(1, '董事长', '管理整个公司,接单'),
(2, '经理', '管理部门员工'),
(3, '销售员', '向客人推销产品'),
(4, '文员', '使用办公软件');

-- 11111111111111111111111111111111111111111111111111111111111111111111员工表
CREATE TABLE emp (
  id INT PRIMARY KEY, -- 员工id
  ename VARCHAR(50), -- 员工姓名
  job_id INT, -- 职务id
  mgr INT , -- 上级领导
  joindate DATE, -- 入职日期
  salary DECIMAL(7,2), -- 工资
  bonus DECIMAL(7,2), -- 奖金
  dept_id INT, -- 所在部门编号
  CONSTRAINT emp_jobid_ref_job_id_fk FOREIGN KEY (job_id) REFERENCES job (id),
  CONSTRAINT emp_deptid_ref_dept_id_fk FOREIGN KEY (dept_id) REFERENCES dept (id)
);
-- 添加员工
INSERT INTO emp(id,ename,job_id,mgr,joindate,salary,bonus,dept_id) VALUES 
(1001,'孙悟空',4,1004,'2000-12-17','8000.00',NULL,20),
(1002,'卢俊义',3,1006,'2001-02-20','16000.00','3000.00',30),
(1003,'林冲',3,1006,'2001-02-22','12500.00','5000.00',30),
(1004,'唐僧',2,1009,'2001-04-02','29750.00',NULL,20),
(1005,'李逵',4,1006,'2001-09-28','12500.00','14000.00',30),
(1006,'宋江',2,1009,'2001-05-01','28500.00',NULL,30),
(1007,'刘备',2,1009,'2001-09-01','24500.00',NULL,10),
(1008,'猪八戒',4,1004,'2007-04-19','30000.00',NULL,20),
(1009,'罗贯中',1,NULL,'2001-11-17','50000.00',NULL,10),
(1010,'吴用',3,1006,'2001-09-08','15000.00','0.00',30),
(1011,'沙僧',4,1004,'2007-05-23','11000.00',NULL,20),
(1012,'李逵',4,1006,'2001-12-03','9500.00',NULL,30),
(1013,'小白龙',4,1004,'2001-12-03','30000.00',NULL,20),
(1014,'关羽',4,1007,'2002-01-23','13000.00',NULL,10);

-- 1111111111111111111111111111111111111111111111111111111111111111工资等级表
CREATE TABLE salarygrade (
  grade INT PRIMARY KEY,
  losalary INT,
  hisalary INT
);
-- 添加5个工资等级
INSERT INTO salarygrade(grade,losalary,hisalary) VALUES 
(1,7000,12000),
(2,12010,14000),
(3,14010,20000),
(4,20010,30000),
(5,30010,99990);

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

9.事务:一组操作,要么同时成功,要么同时失败

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如下若在执行一次sql前执行一次start transaction,若不commit,刷新数据库不显示。
在这里插入图片描述

10.四个接口:左java.sql包下的DCSR,右com.mysql.jdbc.Driver

在这里插入图片描述
在这里插入图片描述
如下mchange. .和c3p0. .一起。第一个导入的是mysql-connector…。
在这里插入图片描述
如下代码第一行new Driver()是导入com.mysql.jdbc(用mysql实现好的,就是上面导入的mysql-connector..jar包)而不是java.sql(自己不会重写抽象方法)下,参数是接口类型需要传入接口的实现类对象即new Driver()。registerDriver相当于set方法,get获取的是mysql.Driver.connect方法返回的Connection类即com.mysql.jdbc.JDBC4Connection(有mysql.的都是导入的jar包)。

加载DriverManager这个类用到打破双亲类加载:DriverManager是jdk自带的类,DriverManager类使用的是bootstrap引用类加载器。数据库是用户类用bootstrap加载不合适,所以DriverManager去加载h2的Driver需要把当前引用类加载器替换为当前系统或当前线程的应用app类加载器
在这里插入图片描述

package com.itheima01.jdbc;
import com.mysql.jdbc.Driver;
import java.sql.*;

public class JdbcDemo { 
    public static void main(String[] args) throws SQLException, ClassNotFoundException, IllegalAccessException, InstantiationException {
        //1. 注册驱动 (注意: 导入的mysql的驱动)
        /*
        *   A. 查看mysql.Driver源码: 点new Driver()中Driver看源码
        *       发现static 代码块里 已经注册了驱动 -> 驱动自注册 相当于set一次就行
        *       带来问题: 外部的注册没有意义(重复注册)
        * 
        *       解决: 保证mysql.Driver类被加载(静态代码块就会执行),如下两种方案:
        *          1. 创建对象
        *          2. 反射:a. 节省内存
        *                  b. 跟驱动包的关联只剩一个字符串:"com.mysql.jdbc.Driver"
        *          待会将字符串写入配置文件,只要改配置文件就行 就会跟 mysql驱动包的彻底解耦 
        */

//111111111111111111111111111111111111111111111111111111111111111111111111111111111111
// DriverManager.registerDriver(new Driver()); //这行重复注册,下行new了就会加载 源码里的静态代码块,所以这行=下行

//new Driver(); // Class对象 + 普通实例 //只要用了这个类,这个类就会被加载内存中方法区 //自动导包
        // new Driver()的内存消耗等价于下面两行: 其实只需要calss对象,不需要实例                  
		// Class<?> clazz = Class.forName("com.mysql.jdbc.Driver"); //获取这个类的class对象
		// Object obj = clazz.newInstance(); //利用class对象调用其空参构造来创建一个实例

        Class.forName("com.mysql.jdbc.Driver"); //获取Class对象,没有普通实例,因为普通实例没有意义 //用反射,com.mysql.jdbc.Driver这个类也会被加载

//111111111111111111111111111111111111111111111111111111111111111111111111111111111111
		 //2. 获取连接
        /*
        *   只要涉及两个软件通信 : 网络三要素(必要非充分:一定要,但是有它们三不一定够如多了资源位置)
        *       1. 协议 :       jdbc:mysql  (主协议:子协议)
        *       2. ip :         数据库所在的计算机(自己:localhost或127.0.0.1)
        *       3. port :       mysql数据库3306
        *       资源位置:   数据仓库的名称
        *       
        *       协议://ip:port/资源位置
        *       https://www.baidu.com:443
        */
//        String url = "jdbc:mysql://localhost:3306/day03";  //day03是数据库
        String url = "jdbc:mysql:///day03"; //ip:localhost port:3306 可以省略
        String user = "root";
        String pwd = "1234";
        Connection conn = DriverManager.getConnection(url, user, pwd);
        System.out.println("conn:" + conn); //引用类型打印地址
        
//1111111111111111111111111111111111111111111111111111111111111111111111111111111111
		 //3. 创建执行sql的语句对象
        /*
        * Connection 接口的一些方法
        *   <1>. Statement createStatement();   创建执行sql的语句对象,相当于创建一个流
        *   <2>. PreparedStatement prepareStatement(sql); 创建一个预编译sql的语句对象
        *   <3>. 事务操作相关
        */
        Statement statement = conn.createStatement();
        System.out.println("statement:" + statement);
        
//11111111111111111111111111111111111111111111111111111111111111111111111111111111111
		  //4. 执行sql,返回结果
		 /*
        * Statetment 接口的api
        *   1. ResultSet statement.executeQuery(sql);
        *           执行的查询语句 : DQL
        *           返回的查询结果: 结果集
        * 
        *   2. int executeUpdate(sql) :
        *           执行的增删改语句: DML
        *           返回的结果: 被影响的行数
        * 
        *   3. boolean execute(sql);  -> 不需要掌握,知道即可
        *               万能 :  DDL等 如create成功或失败是和异常相关,和返回值无关
        *               返回值: 非查询语句返回false,查询语句返回true
        */
        String sql = "select * from emp";
        ResultSet resultSet = statement.executeQuery(sql);
        
//11111111111111111111111111111111111111111111111111111111111111111111111111111111111 
		//5. 处理结果
        while(resultSet.next()){
            String name = resultSet.getString("name");            
// String id = resultSet.getString("id"); //也可以,java程序以外的所有数据对java来说都是字符串
            int id = resultSet.getInt("id"); //底层先调用getString再parse int
            System.out.println(id+ ":" + name);
        }
 
//11111111111111111111111111111111111111111111111111111111111111111111111111111111111
		 //6. 释放资源
        resultSet.close();
        statement.close();
        conn.close();
    }
}

在这里插入图片描述
resultset不是返回一行数据,而是带有id=…。因为返回一行数据如 11孙悟空男,不知道怎么解析。
在这里插入图片描述
如下hasNext和next区别。
在这里插入图片描述

11.释放资源:finally,工具类封装

package com.itheima04.release;
import com.itheima05.utils.JdbcUtil;
import java.io.Closeable;
import java.io.IOException;
import java.sql.*;

public class ReleaseDemo {
    public static void main(String[] args)  {
        ResultSet resultSet = null;
        Statement statement = null;
        Connection conn = null;
        try {
            /*Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/day03";
            String user = "root";
            String pwd = "1234";
            conn = DriverManager.getConnection(url, user, pwd);*/
            
            conn = JdbcUtil.getConnection(); //查询要获取连接,getConnection方法调用多遍,所以getConnection方法不写try catch,查询提示 查询失败,删除提示 删除失败,封装时不知道是查询还是删除,不好提示,所以往外抛。
            conn = JdbcUtil.getConnection(); //增删改也要获取连接

//1111111111111111111111111111111111111111111111111111111111111111111111111            
            statement = conn.createStatement();
            String sql = "select * from emp"; 
                                   
            resultSet = statement.executeQuery(sql);            
            while(resultSet.next()){
                String name = resultSet.getString("name");
                System.out.println(name);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally{
           /* if(resultSet != null){
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(statement != null){
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }*/
            
		   // closeIo(resultSet,statement,conn);
            JdbcUtil.release(conn,statement,resultSet);
        }
    }

//1111111111111111111111111111111111111111111111111111111111111111111111
    private static void closeIo(AutoCloseable... ios) { //AutoCloseable接口位于java.lang包下,不用导包
        for (AutoCloseable io : ios) {
            if(io != null){
                try {
                    io.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
package com.itheima05.utils;
import java.sql.*;
/**
*   工具类:  0. 拥有很多 工具方法(重复的代码封装) 的类
*           	命名规范: utils 包 -> xxUtil 类 (xx : 某个模块的名称)
*          		Objects,Arrays,Collections...(JDK提供的)
* 
*          1. 一般工具类中方法是静态的,不用实例化,节省内存
* 
*      	   2. 封装方法的步骤
*         	  1. 先把要把封装的代码写出来
*        	  2. 观察不断重复的部分
*         	  3. 定义方法,然后直接复制过来
*         	  4. 设置参数和返回值
* 
*       注意点: 1. 扩展性 : 不要导入mysql包中的类, 要导入java包中的类(这样换成oracle也可用)
*               2. 工具类中的异常一般是往外抛 : 一般异常是要在业务中处理
*/
public class JdbcUtil {
    static{
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

//1111111111111111111111111111111111111111111111111111111111111111111111111111111
    public static Connection getConnection() throws SQLException {
        //此方法会被多次调用,注册驱动只需要一次 -> 所以用静态代码块 如上
//        Class.forName("com.mysql.jdbc.Driver");
        String url = "jdbc:mysql://localhost:3306/day03";
        String user = "root";
        String pwd = "1234";
        Connection conn = DriverManager.getConnection(url, user, pwd);
        return conn;
    }
    
//1111111111111111111111111111111111111111111111111111111111111111111111111111111
    /**
     * 文档注释: a. 写在类上面 : 描述类的用途
     *      	 b. 写在方法上面 : 描述方法的用途 (返回值,参数)
     */
   public static void release(Connection conn, Statement statement, ResultSet resultSet){
   	   //java.sql.Connection
       if(resultSet != null){
           try {
               resultSet.close();
           } catch (SQLException e) {
               e.printStackTrace();
           }
       }
       if(statement != null){
           try {
               statement.close();
           } catch (SQLException e) {
               e.printStackTrace();
           }
       }
       if(conn != null){
           try {
               conn.close();
           } catch (SQLException e) {
               e.printStackTrace();
           }
       }
   }
}

如下改进上面工具类。

/*
*   问题: 驱动,url,用户名和密码等信息 是有可能会变的, 变动频率比较低
*       1. 如果不变,直接写死在代码中
*       2. 变,但是频率高 : 一般设置成参数
*       3. 变,但是频率不高: 放在配置文件
*           1. 解耦 : 信息要改变的话,只要改配置文件,代码不用改,程序不需要重新编译和部署
*           2. 代码简化 : 无需调用的时候传参了
*/
//jdbc.properties文件,每个月改一次 //文件里没有关键字,也没有双引号,本来就是字符串
driverName = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/day03
user = root
pwd = 1234
package com.itheima05.utils;
import java.io.FileInputStream;
import java.sql.*;
import java.util.Properties;

public class JdbcUtil02 {
    static String driverName;
    static String url;
    static String user;
    static String pwd;
    static{
        try {
            Properties p = new Properties();
            p.load(new FileInputStream("src/jdbc.properties"));
                        
            driverName = p.getProperty("driverName");
            url = p.getProperty("url");
            user = p.getProperty("user");
            pwd = p.getProperty("pwd");
            
            Class.forName(driverName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }   

//1111111111111111111111111111111111111111111111111111111111111111111111111111111111
    public static Connection getConnection() throws SQLException {
        Connection conn = DriverManager.getConnection(url, user, pwd);
        return conn;
    }

//11111111111111111111111111111111111111111111111111111111111111111111111111111111111 
   public static void release(Connection conn, Statement statement, ResultSet resultSet){
       if(resultSet != null){
           try {
               resultSet.close();
           } catch (SQLException e) {
               e.printStackTrace();
           }
       }
       if(statement != null){
           try {
               statement.close();
           } catch (SQLException e) {
               e.printStackTrace();
           }
       }
       if(conn != null){
           try {
               conn.close();
           } catch (SQLException e) {
               e.printStackTrace();
           }
       }
   }
}

12.JDBC事务操作:conn.setAutoCommit(false)

package com.itheima01.transaction;
import com.itheima.utils.JdbcUtil;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;
// JDBC : 写一个转账案例
public class Demo {
    public static void main(String[] args)  {       
        System.out.println("请输入转出的账户:"); 
        Scanner sc = new Scanner(System.in); // 控制台: 模拟页面
        String outUser = sc.nextLine();
                
        System.out.println("请输入转入的账户:");
        String inUser = sc.nextLine();   
             
        System.out.println("请输入转账的金额:");
        double money = sc.nextDouble();
        
       //sql里面最好写单引号 , 1000和jack改为 两个双引和两个+号
       //String sql1 = "update account set money = money-1000 where name = 'jack'";
        String sql1 = "update account set money = money-"+money+" where name = '"+outUser+"'";
        String sql2 = "update account set money = money+"+money+" where name = '"+inUser+"'";

//11111111111111111111111111111111111111111111111111111111111111111111111111111111111111
        Connection conn = null;
        try {
                /*
                *   事务操作: Connection
                *       1. setAutoCommit(false); 开启事务
                *       2. commit(); 提交事务
                *       3. rollback(); 事务回滚
                *   注意点: 在事务中, 开启事务的连接才具有手动提交事务的功能
                *           一组操作都必须要同一个 连接conn  要执行
                */            
            conn = JdbcUtil.getConnection(); //访问数据库,try外面定义conn
 		   // Connection conn2 = JdbcUtil.getConnection();      		        
            conn.setAutoCommit(false); //开启事务,禁止自动提交  

            Statement statement = conn.createStatement(); 
            statement.executeUpdate(sql1);   //转出                      
            // int i = 1/0;  // ArithmeticException 算术异常 模拟银行爆炸                
            Statement statement2 = conn.createStatement(); 
            statement2.executeUpdate(sql2);   //转入

//1111111111111111111111111111111111111111111111111111111111111111111111111111111111111                  			
            conn.commit(); //提交事务(和事务回滚只有其一执行) 
            System.out.println("转账成功~~");
        } catch (Exception e) { // 注意: 提升异常级别(用于捕获算术异常)
            e.printStackTrace();
            if(conn != null){ //Connection conn放外面,这边访问的到
                try {
                    conn.rollback(); //事务回滚
                } catch (SQLException e1) {
                    e1.printStackTrace();
                }
            }
            System.out.println("转账失败");
        }
    }
}

在这里插入图片描述
在这里插入图片描述

13.登陆案例预编译改造:PreparedStatement,setString,executeQuery

在这里插入图片描述

package com.itheima02.login;
import com.itheima.utils.JdbcUtil;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;
/*
    前提: 用户能够登录,说明已经注册过了
         注册成功的时候, 程序会把用户的信息保存到数据库
          
*   登录案例: 逻辑: 请输入用户名和密码(用户)
*            我们: 校验数据库
*            sql :  select * from account where name = ? and pwd = ?; (name用户名唯一)
*           预测结果:  1. 0条 : 用户名不存在或密码错误
*                     2. 1条 : 登录成功
*/
public class LoginDemo {
    public static void main(String[] args) throws SQLException {
        System.out.println("请输入用户名:");
        Scanner sc = new Scanner(System.in);
        String name = sc.nextLine();  
              
        System.out.println("请输入密码:");
        String pwd = sc.nextLine();
        
        String sql = "select * from account where name = '"+name+"' and pwd = '"+pwd+"'";
        System.out.println(sql); //将参数(上面键盘输入)直接拼接进sql
        
//1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
        Connection conn = JdbcUtil.getConnection();
        Statement statement = conn.createStatement();           
        ResultSet resultSet = statement.executeQuery(sql); //将sql发送给数据库去处理
        if(resultSet.next()){ //有一条则为true
            System.out.println("登录成功~~");
        }else{
            System.out.println("用户名不存在或密码错误");
        }
    }
}

根据(用户名和密码)或(1=1永真)为条件查询数据库,what可以随便写。
在这里插入图片描述
预编译知道了sql的语法结构了,已经把关键字认全了,后面再包含关键字or就不认了(当成字符串处理),可以防止sql注入
在这里插入图片描述

package com.itheima02.login;
import com.itheima.utils.JdbcUtil;
import java.sql.*;
import java.util.Scanner;

public class LoginDemo02 {
    public static void main(String[] args) throws SQLException {
        System.out.println("请输入用户名:");
        Scanner sc = new Scanner(System.in);
        String name = sc.nextLine();  
        System.out.println("请输入密码:");
        String pwd = sc.nextLine();

            // 1. 改造sql       
        String sql = "select * from account where name = ? and pwd = ?";
        System.out.println(sql);
        Connection conn = JdbcUtil.getConnection();

           // 2. 预编译sql   // PreparedStatement 是 Statement的子接口
        PreparedStatement statement = conn.prepareStatement(sql);

          // 3. 设置参数
          // setString(int parameterIndex, String x)
          // parameterIndex : sql中的?的索引(从1开始,从左开始)  // String x: 参数
        statement.setString(1,name);
        statement.setString(2,pwd);

          // 4. 传参执行
        ResultSet resultSet = statement.executeQuery();
        if(resultSet.next()){
            System.out.println("登录成功~~");
        }else{
            System.out.println("用户名不存在或密码错误");
        }
    }
}

在这里插入图片描述
如下手动在数据库中增加一行。
在这里插入图片描述
在这里插入图片描述

package com.itheima03.prepare;
import com.itheima.utils.JdbcUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
/*
*   预编译的好处:  1. 防止sql注入
*                 2. 阅读性强(sql)
*                 3. 批量处理sql,效率高 (节省了sql重复编译过程)
*/
public class PrepareDemo {
    public static void main(String[] args) throws SQLException {
//        method01(); //用预编译,如下不用预编译
        String name = "ww";
        int money = 200;
        String sql1 = "insert into account values(null,'"+name+"',"+money+",null)";

        String name2 = "www";
        int money2 = 2002;
        String sql2 = "insert into account values(null,'"+name2+"',"+money2+",null)";     

        Connection conn = JdbcUtil.getConnection();
        Statement statement = conn.createStatement(); //不用预编译
        statement.executeUpdate(sql1);// 编译+运行
        statement.executeUpdate(sql2);//编译+运行,和上行一共两次编译        
        statement.close();
        conn.close();
    }

//1111111111111111111111111111111111111111111111111111111111111111111111111
    private static void method01() throws SQLException {
        String sql = "insert into account values(null,?,?,null)";        
        Connection conn = JdbcUtil.getConnection();
        PreparedStatement pstm = conn.prepareStatement(sql);   
              
        pstm.setString(1,"zs");
        pstm.setDouble(2,1000);
        pstm.executeUpdate();//运行
        
        pstm.setString(1,"ls");
        pstm.setDouble(2,2000);
        pstm.executeUpdate();//运行        
        pstm.close();
        conn.close();
    }
}

14.c3p0连接池:jdbc2.0才引进连接池,不是线程池(连接池的技术标准就是DataSource替代DriverManager)

在这里插入图片描述

package com.itheima04.c3p0;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class C3p0Demo {  
    public static void main(String[] args) throws PropertyVetoException, SQLException {
//        method01(); //这行方法和下面xml文件无关
        /*
        * 配置文件方式 :   默认情况下, c3p0将会在 类加载器路径(在当前的工程下, src路径)下
        *     寻找一个名为c3p0-config.xml 配置文件(xml文件是复杂的Properties文件,也是key-value)
        * 
        *   套路: 1. 在src下创建名为c3p0-config.xml配置文件(内容直接复制)
        *        2. 创建ComboPooledDataSource核心类      
        */
        ComboPooledDataSource cpds = new ComboPooledDataSource(); 
    //1. 底层自动会去类加载器路径(写代码:src下) 去寻找一个名为c3p0-config.xml 配置文件
   // 2. 自动解析: 读取xml中配置信息 , 设置给c3p0即cpds    

        String sql = "select * from account";  // 同下面              
        Connection conn = cpds.getConnection();  
        PreparedStatement pstm = conn.prepareStatement(sql);
        ResultSet resultSet = pstm.executeQuery();
        while(resultSet.next()){
            String name = resultSet.getString("name");
            System.out.println(name + "--");
        }
        conn.close();// 将连接还给连接池
        cpds.close(); // 销毁
    }

//111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    private static void method01() throws PropertyVetoException, SQLException {
        // 如下硬编码: 用代码来实现参数的设置。一般不用硬编码,用配置文件
        ComboPooledDataSource cpds = new ComboPooledDataSource();//ComboPooledDataSource是DataSource实现类
        cpds.setDriverClass( "com.mysql.jdbc.Driver"); //需要mysql-connector-java-x.x.x-bin.jar
        cpds.setJdbcUrl( "jdbc:mysql://localhost:3306/day05" );
        cpds.setUser("root");
        cpds.setPassword("1234");
        
        String sql = "select * from account";              
        Connection conn = cpds.getConnection();   
        PreparedStatement pstm = conn.prepareStatement(sql);
        ResultSet resultSet = pstm.executeQuery();
        while(resultSet.next()){
            String name = resultSet.getString("name");
            System.out.println(name); //System.err.println(name);//红色
        }
        conn.close();// 将连接还给连接池
        cpds.close(); // 销毁
    }
}
//c3p0-config.xml
<c3p0-config>    
    <default-config>   <!-- 使用默认的配置读取连接池对象 -->
        <!--  如下连接参数 --> 
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/day05</property>
        <property name="user">root</property>
        <property name="password">1234</property>
        <!-- 如下连接池参数 -->
        <!--
            initialPoolSize : 初始化连接数  3
            maxPoolSize: 最大连接数  5
            checkoutTimeout : 连接超时时间 2000ms(默认10s,访问数超过最大连接数, 有人必须要等,2秒连不上给个提示或报错)                        
            maxIdleTime :最大的闲置时间,连接超过maxIdleTime没人使用闲置就销毁maxPoolSize中连接,留到minPoolSize中数量,因为费内存
        -->
        <property name="initialPoolSize">3</property>
        <property name="maxPoolSize">5</property>
        <property name="minPoolSize">2</property>
        <property name="checkoutTimeout">2000</property>
        <property name="maxIdleTime">1000</property>
    </default-config>

<!--111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111-->
    <named-config name="xx">
        <!--  连接参数 -->
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/beitai</property>
        <property name="user">root</property>
        <property name="password">root</property>
        <!-- 连接池参数 -->
        <property name="initialPoolSize">5</property>
        <property name="maxPoolSize">15</property>
        <property name="checkoutTimeout">2000</property>
        <property name="maxIdleTime">1000</property>
    </named-config>
</c3p0-config>
package com.itheima04.c3p0;
import org.junit.Test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class ParseDemo {
    @Test
    public void method01() throws IOException {
        Properties p = new Properties(); //Properties就是一个map            
        p.load(new FileInputStream("src/jdbc.properties")); //相对路径:当前工程src下
        String url = p.getProperty("url"); //.properties文件中有url=...
        System.out.println(url);
    }    

    @Test
    public void method02() throws IOException {
        /*
        *     1. 类加载器 classloader 【底层: 输入流】
        *  作用: 将 .class文件(硬盘) 加载进内存(兼职把jdbc.properties加载进来)。
        * 
        *     2. classloader怎么知道.class文件在哪里?
        *  classloader有个默认加载路径:out路径下项目名路径(src和out/production/项目名路径里文件全一样)。
        * 
        *  相比method01,一般用method02更通用,因为每个工程都会有类加载器路径,但是每个工程的相对路径不一定是当前工程src下。
        *  如web阶段main方法不在项目里,每个项目的入口是main方法,main方法在tomcat里,
        *  所以工程的相对路径会变,但是类加载器的路径不变,一直指向.class文件路径。
        */
        ClassLoader classLoader = ParseDemo.class.getClassLoader(); //利用当前类获取类加载器路径
        InputStream is = classLoader.getResourceAsStream("jdbc.properties"); //获取资源转成流 
        Properties p = new Properties();
        p.load(is);
        String url = p.getProperty("url");
        System.out.println(url + "-2");
    }
}
package com.itheima04.c3p0;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.SQLException;
//c3p0-config.xml验证
public class C3p0Demo02 { 
    public static void main(String[] args) throws SQLException {            
        ComboPooledDataSource ds = new ComboPooledDataSource(); //使用默认配置即c3p0-config.xml中<default-config>            
       // ComboPooledDataSource ds = new ComboPooledDataSource("xx"); //使用命名配置即c3p0-config.xml中<named-config name="xx"> //备胎项目用。               
        for (int i = 0; i < 6; i++) { //循环模拟: 有几多个用户
            Connection conn = ds.getConnection();
            System.out.println(conn); //没有下面close的话,5个连接6个人拿超过2s,会发生timed out报错
            if(i == 3){ //i=3打印了下又还给连接池,所以i=3打印了两次。             
                conn.close(); //验证了确实连接还给连接池
            }
        }
    }
}

5个连接6个人拿是不够的。如下最后@2d…打印了2次并且没有发生timed out连接超时错误。
在这里插入图片描述

15.druid连接池:自动ds.set

package com.itheima05.druid;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

public class DruidDemo {
    public static void main(String[] args) throws Exception {
//        method01();   
        //如下配置文件的方式
        InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
        Properties p = new Properties();
        p.load(is);         
        DataSource ds = DruidDataSourceFactory.createDataSource(p);  //自动解析.properties文件
        
        String sql = "select * from account";        
        Connection conn = ds.getConnection(); //获取连接
        PreparedStatement pstm = conn.prepareStatement(sql);
        ResultSet resultSet = pstm.executeQuery();
        while(resultSet.next()){
            String name = resultSet.getString("name");
            System.out.println(name + "-++");
        }
        conn.close();  //将连接还给连接池
    }

//111111111111111111111111111111111111111111111111111111111111111111111111
    private static void method01() throws SQLException {
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql:///day05");
        ds.setUsername("root");
        ds.setPassword("1234");
        
        String sql = "select * from account";               
        Connection conn = ds.getConnection();  
        PreparedStatement pstm = conn.prepareStatement(sql);
        ResultSet resultSet = pstm.executeQuery();
        while(resultSet.next()){
            String name = resultSet.getString("name");
            System.out.println(name + "--");
        }
        conn.close();// 将连接还给连接池
//       ds.close(); // 销毁 //实际开发服务器不关,连接池不会销毁
    }
}
//druid.properties文件,如下key固定写法
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///day05
username=root
password=1234

封装druid连接池工具类:ds = DruidDataSourceFactory。File-New-Project-Java。
在这里插入图片描述
在这里插入图片描述

package com.itheima.utils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

public class JdbcUtil {
    private static DataSource ds; //下面getConn()也能访问到
    static{ //静态代码块只运行一次
        try {
            Properties p = new Properties();
            InputStream is = JdbcUtil.class.getClassLoader().getResourceAsStream("druid.properties");            
            p.load(is);            
            ds = DruidDataSourceFactory.createDataSource(p); //DataSource ds = 移到最上面了
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static DataSource getDs() { //属性私有化后提供对外公开的方法
        return ds;
    }
    public static Connection getConn() throws SQLException {
//        Connection connection =  ds.getConnection();
//        return connection;
        return ds.getConnection(); //等同上面两行
    }
    public static void release(AutoCloseable... ios){
        for (AutoCloseable io : ios) {
            if(io != null){
                try {
                    io.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
package com.itheima.utils;
import org.junit.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
//测试上面JdbcUtil类
public class TestDemo {
    @Test
    public void method01() throws SQLException {
        String sql = "select * from account";    
        Connection conn = JdbcUtil.getConn();
        PreparedStatement pstm = conn.prepareStatement(sql);
        ResultSet resultSet = pstm.executeQuery();
        while(resultSet.next()){
            String name = resultSet.getString("name");
            System.out.println(name);
        }
        JdbcUtil.release(resultSet,pstm,conn); //注意: conn的close是将连接还给连接池
    }
}

如下是数据库中name这一列,不是.properties文件的key。
在这里插入图片描述

16.execute/update方法:template =

在这里插入图片描述

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. 数据库的操作:DCMQ
*            2. 核心类: 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);
    }
}

17.queryForXX/query方法:Map.Entry < String, Object > ,Map < String, Object > 两个数据类型

一行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}
        }
    }
}
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); //打印出,list里是student类
        // [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()
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/736314.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

文华财经多空精准买卖点止损止盈数值主图指标公式源码

文华财经多空精准买卖点止损止盈数值主图指标公式源码&#xff1a; DD:EVERY(H>HV(H,20),1); KK:EVERY(L<LV(L,20),1); D:DD&&SUM(DD,BARSLAST(KK))1; K:KK&&SUM(KK,BARSLAST(DD))1; Y:1; DRAWCOLORKLINE(Y&&ISDOWN,COLORYELLOW,0); DRAW…

How to create a langchain doc from an str

问题背景&#xff1a; Ive searched all over langchain documentation on their official website but I didnt find how to create a langchain doc from a str variable in python so I searched in their GitHub code and I found this : 在 langchain 的官方文档中&#…

吴恩达机器学习 第二课 week4 决策树

目录 01 学习目标 02 实现工具 03 问题描述 04 构建决策树 05 总结 01 学习目标 &#xff08;1&#xff09;理解“熵”、“交叉熵&#xff08;信息增益&#xff09;”的概念 &#xff08;2&#xff09;掌握决策树的构建步骤与要点 02 实现工具 &#xff08;1&#xff09;…

视频讲解|【双层模型】分布式光伏储能系统的优化配置方法

1 主要内容 该讲解视频对应的程序链接为【双层模型】分布式光伏储能系统的优化配置方法&#xff0c;模型参考《分布式光伏储能系统的优化配置方法》&#xff0c;分为上下层求解方式&#xff0c;上层采用粒子群算法确定储能的选址和容量方案&#xff0c;以全年购电成本、网络损…

<router-view />标签的理解

< router-view />标签的理解 < router-view />用来承载当前级别下的子集路由的一个视图标签。显示当前路由级别下一级的页面。 App.vue是根组件&#xff0c;在它的标签里使用&#xff0c;而且配置好路由的情况下&#xff0c;就能在浏览器上显示子组件的效果。 如…

开启调试模式

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 run()方法虽然适用于启动本地的开发服务器&#xff0c;但是每次修改代码后都要手动重启它。这样并不够方便&#xff0c;如果启用了调试支持&#xff…

中国真实婚恋相亲交友服务平台有哪些?全国靠谱恋爱脱单软件APP大全

终于成功脱单了&#xff01;在过去的这两年里&#xff0c;我动用了身边所有的资源&#xff0c;却始终未能找到理想的男朋友。无奈之下&#xff0c;只好将目光转向线上。经过长达半年的不懈坚持&#xff0c;终于寻觅到了心仪的对象&#xff01;接下来&#xff0c;我要把自己用过…

【PL理论深化】(2) 语法分析 (Syntax) | 编程语言的语法结构:文法 | 语义结构 (Sematics)

&#x1f4ac; 写在前面&#xff1a;编程语言是由归纳法生成的程序的集合。定义属于该语言的程序的形式的规则&#xff0c;即编写程序的规则&#xff0c;称为编程语言的 语法分析 (syntax) 而定义属于该语言的程序的意义的规则称为 语义结构(semantics)。这两者都是归纳定义的。…

QML 列表,图片展示(一)

文章目录 1.QML 列表&#xff0c;图片展示效果图2.项目基本说明3.项目详解3.1界面显示部分3.2 网络部分 4.源代码5.flickr图片查询链接&#xff0c;后面我们将调整代码&#xff0c;获取更多图片 1.QML 列表&#xff0c;图片展示效果图 2.项目基本说明 该项目来自Qt示例程序 Ph…

LabVIEW电路板故障诊断系统

基于LabVIEW软件开发的电路板故障诊断系统&#xff0c;涵盖功能测试、性能测试和通讯测试等多个方面。系统集成了多种硬件设备&#xff0c;包括NI PXI-1033机箱、NI PXI-4071数字万用表、NI PXI-4130电源模块、NI PXI-8512 CAN模块等&#xff0c;通过模块化设计实现了对电路板的…

HarmonyOS SDK助力鸿蒙原生应用“易感知、易理解、易操作”

6月21-23日&#xff0c;华为开发者大会&#xff08;HDC 2024&#xff09;盛大开幕。6月23日上午&#xff0c;《HarmonyOS开放能力&#xff0c;使能应用原生易用体验》分论坛成功举办&#xff0c;大会邀请了多位华为技术专家深度解读如何通过根技术、开放能力、场景化控件等亮点…

面向对象修炼手册(三)(行为与多态)(Java宝典)

​ &#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;面向对象修炼手册 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 前言 行为 1 静态行为和动态…

技术管理转型之战:解锁管理新境界——直觉决策的艺术与科学

文章目录 引言一、直觉决策的定义与特点二、直觉决策在管理中的价值三、直觉决策的来源1、潜意识的心里过程2、基于价值观或道德的决策3、基于经验的决策4、影响发动的决策5、基于认知的决策 四、如何培养直觉决策能力五、直觉决策的风险与应对结语 引言 在快速变化的商业环境…

查找和排序

目录 一、查找 1.1查找的基本概念 1.2顺序查找 1.3折半查找&#xff08;二分查找&#xff09; 1.4散列表的查找 1.4.1基本概念 1.4.2散列函数的构造方法 1.4.3解决冲突的方法 二、排序 2.1排序的基本概念 2.2插入排序 2.2.1直接插入排序&#xff1a; 2.2.2希尔排序…

CSS属性选择器学习记录(4)

目录 1、CSS 属性 选择器 1.1、CSS [attribute|value] 选择器 1.2、实例 2、具有特定属性的HTML元素样式 3、属性选择器 4、属性和值选择器 5、属性和值的选择器 - 多值 6、表单样式 1、CSS 属性 选择器 顾名思义&#xff0c;CSS 属性选择器就是指可以根据元素的属性以…

Centos7 Mysql8.3.0 安装地址

MySQL :: Download MySQL Community Server (Archived Versions)

力扣SQL50 查询近30天活跃用户数 datediff(日期1,日期2)

Problem: 1141. 查询近30天活跃用户数 &#x1f468;‍&#x1f3eb; 参考题解 -- 选择活动日期作为天数&#xff0c;计算每天的唯一活跃用户数 select activity_date as day, count(distinct user_id) as active_users from activity -- 从2019年7月27日开始的30天内 where …

c#考试知识点

第一题 //数组{1&#xff0c;2&#xff0c;3&#xff0c;&#xff0c;8&#xff0c;6} //方法&#xff08;数组&#xff0c;目标值&#xff09; //输出 //接收一个数组&#xff0c;输出目标值是数组中哪两个数的和&#xff0c;并输出下标 using System; using System.Collectio…

《三国:谋定天下》成为了SLG游戏现象级的成功案例

原标题&#xff1a;《三国&#xff1a;谋定天下》引领SLG游戏新潮流&#xff0c;B站股价五个飙升了30% 易采游戏网6月23日&#xff1a;B站作为年轻人喜爱的文化社区和视频平台&#xff0c;再次用一款新的游戏证明了其在游戏发行领域的独到眼光与强大实力。最近大火的策略角色扮…

【python】python海底捞门店营业数据分析与可视化(数据集+源码+论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…