如果使用JDBC来操作MySQL数据库

本章是关于JDBC 的相关内容,模拟JDBC操作数据库。源码和jar包获取:https://gitee.com/it-sherlock/jdbc-source-code

1. 数据库驱动

一般分是三个部分,先是,调用JDBC这一部分;然后调用JDBC驱动;最后,访问数据库。
在这里插入图片描述

2. JDBC

SUN公司为了简化,开发人员的(对数据库的统一)操作,提供了一个(Java操作数据库)

这些规范的实现由具体的厂商去做。

对于开发人员来说,我们只需要掌握JDBC的操作就可以了。

JDBC驱动下载:https://mvnrepository.com/artifact/mysql/mysql-connector-java

3. 第一个 JDBC 程序

创建测试的数据库:

CREATE DATABASE jdbcStudy CHARACTER SET utf8 COLLATE utf8_general_ci;

USE jdbcStudy

CREATE TABLE users(
	id INT PRIMARY KEY,
	`name` VARCHAR(40),
	`password` VARCHAR(40),
	email VARCHAR(60),
	birthday DATE
);

INSERT INTO users (id,`name`,`password`,email,birthday) 
VALUES (1,'zhangsan','123456','zs@qq.com','1999-11-01'),(2,'lisi','123456','ls@qq.com','1229-11-01'),(3,'wangwu','123456','ww@qq.com','2009-11-01');

1. 创建一个项目。
在这里插入图片描述
2. 导入数据库驱动jar包。
在这里插入图片描述
3. 编写测试代码。

package com.zhangsan.demo01;

import java.sql.*;

// 我的第一个jdbc程序
public class JdbcFistDemo {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        // 1. 加载驱动
        Class.forName("com.mysql.jdbc.Driver"); // 固定写法,加载驱动

        // 2. 用户信息和url
        // 三个参数:useUnicode=true&characterEncoding=utf8&useSSL=true
        // useUnicode=true :支持中文编码
        // characterEncoding=utf8 :设置字符集为utf8
        // useSSL=true :使用安全的连接
        String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
        String username = "root";
        String password = "123456";

        // 3. 连接成功,数据库对象 这里的connection代表数据库
        Connection connection = DriverManager.getConnection(url,username,password);

        // 4. 执行sql的对象 Statement用来执行sql的
        Statement statement = connection.createStatement();
        // 5. 执行sql
        String sql = "SELECT * FROM users";
        // resultSet :返回的结果集,结果集中封装了我们全部的查询结果
        ResultSet resultSet = statement.executeQuery(sql);

        while (resultSet.next()){
            System.out.println("id = " + resultSet.getObject("id"));
            System.out.println("name = " + resultSet.getObject("name"));
            System.out.println("pwd = " + resultSet.getObject("password"));
            System.out.println("email = " + resultSet.getObject("email"));
            System.out.println("birthday = " + resultSet.getObject("birthday"));
            System.out.println("===============================================");
        }
        // 6. 释放连接(关闭连接)
        // 关闭连接的顺序刚好是反着的
        resultSet.close();
        statement.close();
        connection.close();
    }
}

步骤总结:

  • 1.加载驱动,Class.forName(“com.mysql.jdbc.Driver”);
  • 2.连接数据库 DriverManager
  • 3.获得执行sql的对象 Statement
  • 4.获得返回的结果集 ResultSet
  • 5.释放连接(关闭连接)

DriverManager:

// DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.jdbc.Driver"); // 固定写法,加载驱动
//其实上面的forName就是调用的DiverManager中的registerDriver,使用上推荐使用forName。
//它们两个功能都是一样的,加载驱动



// connection 代表的就是数据库。
Connection connection = DriverManager.getConnection(url,username,password);

// 前面在mysql中所说的事务回滚,事务提交,数据库设置为自动提交,都可以通过connection来操作。
connection.rollback();
connection.commit();
connection.setAutoCommit();

URL:

// 三个参数:useUnicode=true&characterEncoding=utf8&useSSL=true
// useUnicode=true :支持中文编码
// characterEncoding=utf8 :设置字符集为utf8
// useSSL=true :使用安全的连接
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";

//mysql 默认端口号:3306
//mysql的URL格式:
//jdbc:mysql://主机地址:端口号/数据库名?参数1&参数2&参数3

//oracle 默认端口号:1521
//oracle的URL格式:
//jdbc:oracle:thin:@localhost:1521:sid

//像jdbc:mysql 或者 jdbc.oracle 这些都是一种协议。

Statement执行SQL对象:(还有一个PrepareStatement 也是执行sql对象的)

String sql = "SELECT * FROM users"; // 编写sql

statement.executeQuery("sql语句"); //查询操作,返回resultSet。
statement.execute("sql语句"); //可以执行任何sql,它能执行任何sql就说明它会有一个判断形式,性能比其他语句低。
statement.executeUpdate("sql语句"); // 更新,插入,删除,都是用update操作。
statement.executeBatch("sql语句"); //可以存放多个sql语句,执行。

ResultSet 查询的结果集:封装了所有的查询结果

ResultSet resultSet = statement.executeQuery(sql);


resultSet.getObject("列名"); //在不知道列类型的情况下使用,getObject()

//如果知道列的类型就是用指定类型
resultSet.getString("列名");
resultSet.getInt("列名");
resultSet.getFloat("列名");
resultSet.getDate("列名");
...

ResultSet结果集的遍历,指针操作:

resultSet.beforeFirst(); // 移动到最前面
resultSet.afterLast(); // 移动到最后面
resultSet.next();  // 移动到下一个数据
resultSet.previous(); //移动到前一行
resultSet.absolute(row); //移动到指定行

释放资源:

resultSet.close();
statement.close();
connection.close(); 
// 一定要释放资源,用完关掉!不然占内存。

4. statement 对象

JDBC中的statement对象用于向数据库发送SQL语句,向完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。

  • statement对象中的executeUpdate方法,用于向数据库发送增删改查的sql语句,它返回的是一个整数(即增删改语句导致了数据库几行数据发生了变化)。
  • statement.executeQuery方法用于像数据库发送查询语句,它返回一个ResultSet对象数据集。

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

封装数据:

db.properties 文件:用来存储连接数据库的内容。

// db.properties文件:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
username=root
password=123456

JdbcUtiles文件:获取db.properties文件内容,驱动加载,获取连接和释放连接操作。

// JdbcUtils文件:

package com.zhangsan.demo02.utils;

import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class JdbcUtils {

    private static String driver = null;
    private static String url = null;
    private static String username = null;
    private static String password = null;

    static {
        try {
            //获取db.properties的文件,因为在src下,因此不用链接地址。 这里会返回一个输入流
            InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");

            Properties properties = new Properties();
            properties.load(in); // 读取字节流种的属性列表

            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");


            //1. 驱动加载
            Class.forName(driver);



        }catch (Exception e){
            e.printStackTrace();
        }
    }

    // 获取连接
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url,username,password);
    }

    //释放连接资源
    public static void release(Connection con, Statement st, ResultSet rs){
        if (rs!=null){
            try{
                rs.close();
            } catch (SQLException e){
                e.printStackTrace();
            }
        }

        if (st!=null){
            try{
                st.close();
            } catch (SQLException e){
                e.printStackTrace();
            }
        }

        if (con!=null){
            try{
                con.close();
            } catch (SQLException e){
                e.printStackTrace();
            }
        }
    }

}

操作sql语句的文件:增删改查。

//步骤都是一样,就是通过修改sql语句实现。注意是select查询语句有resultset返回集。

package com.zhangsan.demo02;

import com.zhangsan.demo02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestUpdate {
    public static void main(String[] args) {

        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils.getConnection(); // 获取数据库连接
            st = conn.createStatement(); //获得sql的执行对象
            String sql = "UPDATE users SET `name`='张三',`email`='无' WHERE id=3";

            int i = st.executeUpdate(sql);
            if (i>0){
                System.out.println("更新成功|!!");
            }
        } catch(SQLException e){
            e.printStackTrace();
        } finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

SQL注入的问题:

sql存在漏洞,会被攻击导致数据泄露,换句话说就是将SQL语句进行拼接。

在这里插入图片描述

package com.zhangsan.demo02;

import com.zhangsan.demo02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class SQL注入 {
    public static void main(String[] args) {
        //这样我们可以通过login链接数据库完成登录
        //login("张三","123456");

        //sql注入别的语句操作,这里通过拼接其他的sql语句即便没有密码用户,照样能获取数据库信息。
        login("' or '1=1","' or '1=1");

    }

    // 登录业务
    public static void login(String username,String password){
        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils.getConnection(); // 获取数据库连接
            st = conn.createStatement(); //获得sql的执行对象
            String sql = "SELECT * FROM users WHERE `name` = '"+username+"' AND `password` = '"+password+"'";

            rs = st.executeQuery(sql);

            while (rs.next()){
                System.out.println(rs.getString("name"));
                System.out.println(rs.getString("password"));
                System.out.println("===================================");
            }
        } catch(SQLException e){
            e.printStackTrace();
        } finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

5. PreparedStatement 对象

PreparedStatement 可以防止SQL注入,并且效率更高。

PreparedStatement是继承了Statement这个类。

依照上面sql注入,采用preparedstatement就可以有效的避免:

package com.zhangsan.demo02;

import com.zhangsan.demo02.utils.JdbcUtils;

import java.sql.*;

public class SQL注入 {
    public static void main(String[] args) {
        //这样我们可以通过使用PreparedStatement就避免了SQL注入的问题。
        //login("老铁","123456");
        login("' or '1=1","' or '1=1");

    }

    // 登录业务
    public static void login(String username,String password){
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils.getConnection();

            String sql = "SELECT * FROM users WHERE `name` = ? AND `password` = ?";

            // PreparedStatement 防止SQL注入的本质,把传递进来的参数当作字符。
            // 假设其中存在转移字符,比如说: ' 会被直接转义。
            st = conn.prepareStatement(sql);
            st.setString(1,username);
            st.setString(2,password);

            rs = st.executeQuery();

            while (rs.next()){
                System.out.println(rs.getString("name"));
                System.out.println(rs.getString("password"));
                System.out.println("===================================");
            }
        } catch(SQLException e){
            e.printStackTrace();
        } finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

通过PreparedStatement进行的查询操作(增删改也是一样的。):

package com.zhangsan.demo03;

import com.zhangsan.demo02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class TestSelect {
    public static void main(String[] args) {

        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils.getConnection();

            String sql = "select * from users where id=?";

            st = conn.prepareStatement(sql);

            st.setInt(1,1);

            rs = st.executeQuery();

            if(rs.next()){
                System.out.println(rs.getString("name"));
            }


        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

6. 使用IDEA连接数据库

打开IDEA,右侧的Database找到MySQL:
(远程阿里云数据库需要用到它的外网地址查询)

在这里插入图片描述
在这里插入图片描述
Schemas中选择和查看数据库:
在这里插入图片描述
在这里插入图片描述
修改数据,一定要提交:
在这里插入图片描述
在intellij idea 中使用sql语句远程操作数据库:
在这里插入图片描述
在这里插入图片描述

7. 事务

要么都成功,要么都失败。

1. 开启事务 :conn.setAutoCommit(false);
2. 一组业务执行完毕后,要提交事务: conn.commit()。
3. 可以在catch语句中显示定义回滚语句,并且不定义也是默认回滚的!

创建一个模拟事务的java代码:

package com.zhangsan.demo04;

import com.zhangsan.demo02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class TestTransaction {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;

        try{
            conn = JdbcUtils.getConnection();

            conn.setAutoCommit(false); // 关闭自动提交事务

            //实现一次转账
            String sql1 = "update account set money = money-100 where name='A'";
            st = conn.prepareStatement(sql1);
            st.executeUpdate();

            int x = 1/0; //模拟失败后,是否回滚

            String sql2 = "update account set money = money+100 where name='B'";
            st = conn.prepareStatement(sql2);
            st.executeUpdate();

            //如果两个都成功就要提交事务
            conn.commit(); //提交事务
            System.out.println("提交事务,成功!");

        } catch (Exception e) {
            //如果不写也会回滚,默认就是回滚。
            try{
                System.out.println("回滚事务");
                conn.rollback(); // 如果失败则回滚事务
            }catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }

    }
}

8. 数据库连接池

对于上面JDBC的过程:

数据库连接 – 执行完毕 – 释放

但是,这个过程一步步是非常浪费时间的,因此才有了池化技术。

已下几个名词要熟记:

池化技术:准备一些预先的资源,过来就连接预先准备好的。

常用连接数:就是平时多少人连接的数量。

最小连接数:这里的最小连接数,最好和常用连接数相同或大点。

最大连接数:最大连接数就是业务最高的承载上限!

排队等待:如果超过了最大连接数,就要排队等待,等待有人释放了连接。

等待超时:超过一定的时间就会结束这次连接,告诉等待者已经超时或报错。

编写连接池,实现一个接口 DataSource。

开源数据源实现:

DBCP

C3P0

Druid(阿里巴巴)

使用了这些数据库连接池之后,我们在项目开发中就不需要编写连接数据库的代码了(connection,preparedstatement一系列操作)。

DBCP:

需要的jar包:

commons - dbcp - 版本.jar
commons - pool - 版本 .jar

dbcpconfig.properties文件:

# 连接设置 这里面的名字都是DBCP数据源中定义好的,不能乱其名字!!
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
username=root
password=123456


#!-- 初始化连接 --
initialSize=10

#最大连接数量
maxActive=50

#!-- 最大空闲连接 --
maxIdle=20

#!-- 最小空闲连接 --
minIdle=5

#!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60--
maxWait=60000

#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:【属性名=property;】
#注意:user 与 password 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=UTF8

#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true

#driver default 指定由连接池所创建的连接的只读(read-only)状态。
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
defaultReadOnly=

#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED

JdbcUtils_DBCP文件:

package com.zhangsan.demo05.utils;


import org.apache.commons.dbcp.BasicDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class JdbcUtils_DBCP {

    private static DataSource dataSource = null;

    static {
        try {
            //获取db.properties的文件,因为在src下,因此不用链接地址。 这里会返回一个输入流
            InputStream in = com.zhangsan.demo02.utils.JdbcUtils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");

            Properties properties = new Properties();
            properties.load(in); // 读取字节流种的属性列表

            //创建数据源  工厂模式-->创建对象
            dataSource = BasicDataSourceFactory.createDataSource(properties);

        }catch (Exception e){
            e.printStackTrace();
        }
    }

    //获取连接
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection(); //从数据源中获取连接
    }


    //释放连接资源
    public static void release(Connection con, Statement st, ResultSet rs){
        if (rs!=null){
            try{
                rs.close();
            } catch (SQLException e){
                e.printStackTrace();
            }
        }

        if (st!=null){
            try{
                st.close();
            } catch (SQLException e){
                e.printStackTrace();
            }
        }

        if (con!=null){
            try{
                con.close();
            } catch (SQLException e){
                e.printStackTrace();
            }
        }
    }

}

TestDBCP文件:

package com.zhangsan.demo05;

import com.zhangsan.demo05.utils.JdbcUtils_DBCP;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;

public class TestDBCP {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement st = null;

        try{
            conn = JdbcUtils_DBCP.getConnection();

            //Statement和PreparedStatement区别:
            //PreparedStatement可以使用?占位符来代替参数。
            String sql = "INSERT INTO users (id,`name`,`password`,email,birthday) VALUES(?,?,?,?,?)";
            // 预编译SQL,先写sql语句,然后不执行。
            st = conn.prepareStatement(sql);

            // 手动给参数赋值
            st.setInt(1,5); //给?索引为1的问号,赋值为4。
            st.setString(2,"huasheng");
            st.setString(3,"23445");
            st.setString(4,"12345666@qq.com");

            // 注意这里的sql.Date是数据库的;util.Date是java的。
            //这里是将util.Date中获得的时间戳转换为了sql的时间形式。
            st.setDate(5,new java.sql.Date(new Date().getTime()));

            //执行
            int i = st.executeUpdate();
            if(i>0){
                System.out.println("插入成功!!!");
            }

        }catch (SQLException e){
            e.printStackTrace();
        } finally {
            JdbcUtils_DBCP.release(conn,st,null);
        }
    }
}

C3P0:

需要的jar包:

c3p0 - 版本.jar
mchange - commons - java - 版本.jar

C3P0是带日志记录的。

c3p0-config.xml文件:

<?xml version="1.0" encoding="UTF-8"?>

<c3p0-config>

<!--    C3P0的默认配置:如果在代码中"ComboPooledDataSource ds = new ComboPooledDataSource();" 这样写就表示进行C3P0的默认配置。-->
    <default-config>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/first</property>
        <property name="user">root</property>
        <property name="password">199657</property>
        <property name="acquireIncrement">5</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">5</property>
        <property name="maxPoolSize">20</property> <!-- intergalactoApp adopts a different approach to configuring statement
			caching -->
        <property name="maxStatements">0</property>
        <property name="maxStatementsPerConnection">5</property> <!-- he's important, but there's only one of him -->
    </default-config>


<!--    C3P0的命名配置:如果在代码中"ComboPooledDataSource ds = new ComboPooledDataSource("MySQL");"这样写就标识使用的是name为MySQL的配置。-->
    <named-config name="MySQL">
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true;useSSL=true;characterEncoding=utf8</property>
        <property name="user">root</property>
        <property name="password">123456</property>

        <property name="acquireIncrement">5</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">5</property>
        <property name="maxPoolSize">20</property> <!-- intergalactoApp adopts a different approach to configuring statement
			caching -->
        <property name="maxStatements">0</property>
        <property name="maxStatementsPerConnection">5</property> <!-- he's important, but there's only one of him -->
    </named-config>
</c3p0-config>

JdbcUtils_C3P0文件:

package com.zhangsan.demo05.utils;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class JdbcUtils_C3P0 {
    private static ComboPooledDataSource dataSource = null;

    static {
        try {
            //Java代码版配置:可以直接配置内容,但是很麻烦,因此还是推荐配置文件的类型操作。
            //dataSource = new ComboPooledDataSource();
            //dataSource.setDriverClass();
            //dataSource.setUser();
            //dataSource.setPassword();
            //dataSource.setJdbcUrl();
            //dataSource.setMaxPoolSize();
            //dataSource.setMinPoolSize();

            //配置文件写法
            dataSource = new ComboPooledDataSource("MySQL");
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    //获取连接
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection(); //从数据源中获取连接
    }


    //释放连接资源
    public static void release(Connection con, Statement st, ResultSet rs){
        if (rs!=null){
            try{
                rs.close();
            } catch (SQLException e){
                e.printStackTrace();
            }
        }

        if (st!=null){
            try{
                st.close();
            } catch (SQLException e){
                e.printStackTrace();
            }
        }

        if (con!=null){
            try{
                con.close();
            } catch (SQLException e){
                e.printStackTrace();
            }
        }
    }
}

TestC3P0文件:

package com.zhangsan.demo05;

import com.zhangsan.demo05.utils.JdbcUtils_C3P0;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;

public class TestC3P0 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement st = null;

        try{
            conn = JdbcUtils_C3P0.getConnection(); //原来是自己实现,现在用别人的实现

            //Statement和PreparedStatement区别:
            //PreparedStatement可以使用?占位符来代替参数。
            String sql = "INSERT INTO users (id,`name`,`password`,email,birthday) VALUES(?,?,?,?,?)";
            // 预编译SQL,先写sql语句,然后不执行。
            st = conn.prepareStatement(sql);

            // 手动给参数赋值
            st.setInt(1,6); //给?索引为1的问号,赋值为4。
            st.setString(2,"huasheng");
            st.setString(3,"23445");
            st.setString(4,"12345666@qq.com");

            // 注意这里的sql.Date是数据库的;util.Date是java的。
            //这里是将util.Date中获得的时间戳转换为了sql的时间形式。
            st.setDate(5,new java.sql.Date(new Date().getTime()));

            //执行
            int i = st.executeUpdate();
            if(i>0){
                System.out.println("插入成功!!!");
            }

        }catch (SQLException e){
            e.printStackTrace();
        } finally {
            JdbcUtils_C3P0.release(conn,st,null);
        }
    }
}

其实无论怎么使用数据源,它的接口DataSource接口不会变,方法就不会变。

9. 对于JDBC的一些细节补充

9.1 驱动jar版本 和 mysql版本


首先版本,mysql的版本对应的驱动jar包版本,jar包的版本是可以比mysql的版本高的,因为每个jar包版本的设计都会考虑到兼容以前版本。

驱动jar包加载驱动时:

Class.forName(“com.mysql.jdbc.Driver”); 有些版本对应的字节路径,是com.mysql.cj.jdbc.Driver需要注意一下。

9.2 serverTimezone 在mysql8版本是必须设置的一个参数

serverTimezone,在mysql8版本是必须设置的一个参数,我位处于东八区,因此要设定时区!serverTimezone=Asia/Shanghai,这里上海香港都行。这里默认是UTC时区。

Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/emp?serverTimezone=Asia/Shanghai", "root", "0818");

9.3 通过索引来获取字段中的内容

在这里插入图片描述

9.4 executeUpdate()方法返回值是一个整数

executeUpdate()方法返回值是一个整数,因为它代表影响的行数,此外如果他等于0就代表sql语句执行失败或者数据库没有该要操作的数据,因此我们必须要设定好回滚等等操作,避免错误!!!

在这里插入图片描述

10. while循环中next()方法原理

next()方法原理呢,其实就是一个指针,开始指向第一个元素前面的空行(可以这么理解),之后会下调一次判断当前是否有元素,有则返回true,没有则返回false。

在这里插入图片描述

11. Properties文件


我们定义数据配置文件使用的是Properties文件。

这个文件的内容就是key=value形式,注意中间不能有空格和冒号分号之类的。


常用的方法还有如下方式:

  • 第一种方式:通过类加载器方式调用getResourceAsStream(“db.properties”);
package com.demo.test;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;

import org.junit.Test;

public class InputStreamTest {
	@Test
	public void TestInputStream() throws IOException, ClassNotFoundException, SQLException {
		//getClassLoader().getResourceAsStream("db.properties"),加载器方式
		InputStream inputStream = InputStreamTest.class.getClassLoader().getResourceAsStream("db.propertis");
		Properties properties = new Properties();
		properties.load(inputStream);
		
		driver = properties.getProperty("driver");
		url = properties.getProperty("url");
		username = properties.getProperty("username");
		password = properties.getProperty("password");
		
	}
}
  • 第二种方式:还可以通过ResourceBundle.getBundle(“db”)方式,这个方法专门用来接收properties文件,因此不用添加后缀!
package com.demo.test;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
import java.util.ResourceBundle;

import org.junit.Test;

public class InputStreamTest {
	@Test
	public void TestInputStream() throws IOException, ClassNotFoundException, SQLException {
		
		String driver = null;
	    String url = null;
	    String username = null;
	    String password = null;
	    
	    //第二种方式:通过ResourceBundle.getBundle("db")方式,这个方法专门用来接收properties文件,因此不用添加后缀!
	    ResourceBundle bundle = ResourceBundle.getBundle("db");
	    driver = bundle.getString("driver");
	    url = bundle.getString("url");
	    username = bundle.getString("username");
	    password = bundle.getString("password");
		
	}
}

  • 第三种方式:通过当前线程调用getContextClassLoader()方法在调用getResourceAsStream()方法来返回输入流。
package com.demo.test;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
import java.util.ResourceBundle;

import org.junit.Test;

public class InputStreamTest {
	@Test
	public void TestInputStream() throws IOException, ClassNotFoundException, SQLException {
		
		String driver = null;
	    String url = null;
	    String username = null;
	    String password = null;	
	    //第三种方式:通过当前线程调用getContextClassLoader()方法在调用getResourceAsStream()方法来返回输入流。
	    InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties");
	    Properties properties = new Properties();
	    properties.load(in);
	    driver = properties.getProperty("driver");
	    url = properties.getProperty("url");
	    username = properties.getProperty("username");
	    password = properties.getProperty("password");
	    
	}
}

这里解释一下: getClassLoader()是当前类加载器,而getContextClassLoader是当前线程的类加载器。

12. 如何解决java代码向mysql数据库存入年月日时分秒级别的日期


java.sql.date只能精确到年月日,怎么对应数据库精确到时分秒的datetime类型。已解决,使用timestamp对象来操作。

  • Timestamp timestamp = new Timestamp(System.currentTimeMillis());

preparestatement.setTimestamp(1, timestamp);

13. 不常用但是很重要的sql语句


mysql删除外键的指令。

alter table 表名 drop foreign key 字段名;

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xupengboo

你的鼓励将是我创作最大的动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值