JDBC 的使用
使用 MariaDB,JDBC 所有操作全部使用预处理
SQL 的基本类型与 Java 类型的对应关系
CHAR(N) - String
VARCHAR(N) - String
BOOLEN - boolean
BIT - boolean
INT - int
BIGINT - long
FLOAT - float
DOUBLE - double
DECIMAL - BigDecimal
DATE - java.sql.Date
DATETIME - java.util.Date
TIMESTAMP - java.sql.Timestamp
其中 DATE 类型为日期(如 2018 年 12 月 11 日),DATETIME 类型为日期时间(如 2018 年 12 月 11 日 14:10:28.288),还有一点就是 java.sql 包中关于日期的需要 long 类型进行实例化的一般都是用毫秒做单位,如果不幸传入了秒,时间怕就定格在 1970 了
创建数据库与数据表
使用的建表 SQL 文件为 Demo.sql
MariaDB 10.x+ 才支持 DATETIME 设置 CURRENT_TIMESTAMP 或 NOW() 默认值,5.x 及以下需要把 DATETIME 改为 TIMESTAMP 才能使用 CURRENT_TIMESTAMP 或 NOW() 做默认值
CREATE DATABASE `demo`;
-------
USE `demo`;
-------
CREATE TABLE IF NOT EXISTS `userInfo` (
    `rowId` CHAR(36) NOT NULL COMMENT 'MySQL 不支持 DEFAULT UUID()',
    `telNum` CHAR(11) NOT NULL,
    `sex` TINYINT NOT NULL DEFAULT '0' COMMENT '0 为未知,1 为男性,2 为女性',
    `createDate` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `deleteMark` BOOLEAN NOT NULL DEFAULT '0' COMMENT '实际是个 TINYINT(1)',
    PRIMARY KEY (`rowId`),
    UNIQUE KEY `rowId` (`rowId`),
    UNIQUE KEY `telNum` (`telNum`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
------
CREATE TABLE `sendSmsLog` (
    `id` BIGINT NOT NULL AUTO_INCREMENT,
    `userId` CHAR(36) NOT NULL,
    `createDate` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `deleteMark` BOOLEAN NOT NULL DEFAULT '0',
    PRIMARY KEY (`id`),
    KEY `fk_user_info_row_id` (`userId`),
    CONSTRAINT `fk_user_info_row_id` FOREIGN KEY (`userId`) REFERENCES `userInfo` (`rowId`)
) ENGINE=InnoDB AUTO_INCREMENT=1000000 DEFAULT CHARSET=utf8mb4;
导入 SQL,mysql -u root -p < Demo.sql,数据库建立完成
JDBC 的连接前准备
添加 MariaDB 驱动的 Maven 依赖
<!-- MariaDB JDBC 驱动 -->
<dependency>
    <groupId>org.mariadb.jdbc</groupId>
    <artifactId>mariadb-java-client</artifactId>
    <version>2.3.0</version>
    <scope>runtime</scope>
</dependency>
创建连接信息字符串
// JDBC 连接 URL
private static final String JDBC_URL = "jdbc:mariadb://localhost:3306/demo?useSSL=false&characterEncoding=utf8";
// 数据库用户名
private static final String JDBC_USER = "root";
// 数据库密码
private static final String JDBC_PASSWORD = "toor";
驱动的注册与销毁
如果是 JavaEE 程序,则需要先注册驱动器类
try {
    Class.forName("org.mariadb.jdbc.Driver");
} catch (ClassNotFoundException exp) {
    exp.printStackTrace();
}
当然,注册了就得在程序关闭时注销
// 获取加载器,下方需要判断驱动是否是应用自身加载的
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// 获取已加载的所有驱动
Enumeration<Driver> driverEnumeration = DriverManager.getDrivers();
while (driverEnumeration.hasMoreElements()) {
    Driver driver = driverEnumeration.nextElement();
    // 需要直接判断是否是同一个对象,所以使用了 == 而不是 equals(.)
    if (driver.getClass().getClassLoader() == classLoader) {
        try {
            // 注销驱动
            DriverManager.deregisterDriver(driver);
        } catch (SQLException exp) {
            LOGGER.warn("注销驱动异常:" + exp);
        }
    }
}
注册和销毁建议是创建一个 实现了 ServletContextListener 接口的监听器
创建 JDBC 连接
创建链接
try (Connection connection = DriverManager.getConnection(Demo.JDBC_URL, Demo.JDBC_USER, Demo.JDBC_PASSWORD)){
    // TODO SQL 操作
} catch (SQLException exp) {
    System.out.println(exp.getErrorCode() + " - " + exp.getSQLState() + " - " + exp.getMessage());
}
JDBC 插入数据
// 插入操作的 SQL 语句,注意 UUID() 函数的使用,直接作为 SQL 语句传入
final String insertSQL = "INSERT INTO `userInfo`(`rowId`, `telNum`) VALUES (UUID(), ?)";
// 预处理
try (PreparedStatement preparedStatement = connection.prepareStatement(insertSQL)) {
    // 占位符序号从 1 开始
    preparedStatement.setString(1, "13213213213");
    // 返回操作影响的行数
    int effectLine = preparedStatement.executeUpdate();
}
如果该表有自增的主键,那么 prepareStatement() 获取 PreparedStatement 时传入第二个参数 PreparedStatement.RETURN_GENERATED_KEYS,在 executeUpdate() 后通过 ResultSet resultSet = preparedStatement.getGenerateKeys(); long key = resultSet.getLong(1); 即可获取该自增列的值
JDBC 查询数据
// 查询操作的 SQL 语句
final String selectSQL = "SELECT `telNum`, `createDate` FROM `userInfo` WHERE `sex` = ?";
// 预处理
try (PreparedStatement preparedStatement = connection.prepareStatement(selectSQL)) {
    // 传参
    preparedStatement.setInt(1, 0);
    // 只有 SELECT 操作使用 executeQuery() 方法,返回结果集
    try (ResultSet resultSet = preparedStatement.executeQuery()) {
        // 循环获取结果
        while (resultSet.next()) {
            // 通过数据库列名查询
            String telNum = resultSet.getString("telNum");
            // 通过返回数据的列序号查询,从 1 开始
            // DATETIME 类型如果使用 getDate() 方法获取则会失去时间部分
            Timestamp timestamp = resultSet.getTimestamp(2);
            System.out.println(telNum + " - " + timestamp.toInstant());
        }
    }
}
JDBC 更改数据
final String updateSQL = "UPDATE `userInfo` SET `sex` = ? WHERE telNum = ?";
try (PreparedStatement preparedStatement = connection.prepareStatement(updateSQL)) {
    preparedStatement.setInt(1, 1);
    preparedStatement.setString(2, "13213213213");
    int effectLine = preparedStatement.executeUpdate();
}
JDBC 删除数据
一般来说不会真的去删除数据,将 deleteMark 置为 true 即可
final String deleteSQL = "DELETE FROM `userInfo` WHERE `telNum` = ?";
try (PreparedStatement preparedStatement = connection.prepareStatement(deleteSQL)) {
    preparedStatement.setString(1, "13213213213");
    int effectLine = preparedStatement.executeUpdate();
}
JDBC 的事务
Connection connection = null;
// 获取连接
try {
    connection = DriverManager.getConnection(Demo.JDBC_URL, Demo.JDBC_USER, Demo.JDBC_PASSWORD);
    // 设置事务隔离级别
    connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
    // 开启事务
    connection.setAutoCommit(false);
    ///////////////////
    // TODO 执行 SQL
    ///////////////////
    // 执行完成,提交
    connection.commit();
} catch (SQLException exp) {
    // 发生异常,进行回滚
    if (connection != null) {
        connection.rollback();
    }
} finally {
    if (connection != null) {
        // 恢复之前的模式
        connection.setAutoCommit(true);
        connection.close();
    }
}
JDBC 的连接池
这里使用的实现是 HikariCP,Maven 依赖为
<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>3.2.0</version>
    <scope>compile</scope>
</dependency>
HikariCP 的使用
// 初始化 HikariConfig
HikariConfig hikariConfig = new HikariConfig();
// 配置数据库连接信息
hikariConfig.setJdbcUrl(Demo.JDBC_URL);
hikariConfig.setUsername(Demo.JDBC_USER);
hikariConfig.setPassword(Demo.JDBC_PASSWORD);
// 添加一些连接属性
hikariConfig.addDataSourceProperty("connectionTimeout", "1000");
hikariConfig.addDataSourceProperty("idleTimeout", "60000");
hikariConfig.addDataSourceProperty("maximumPoolSize", "10");
// 获取一个 DataSource
DataSource dataSource = new HikariDataSource(hikariConfig);
// 获取 Connection 对象
// close() 方法需要手动调用,即时这不是我们手动初始化的
// 实际上 close() 方法并不是关闭了连接,而是重新释放回连接池
try (Connection connection = dataSource.getConnection()) {
    // TODO SQL 操作
}
// 关闭 Hikari,对于 Web 程序尤其需要注意
((HikariDataSource) dataSource).close();
还有一点,如果使用的是 HikariCP,可以免去手动 Class.forName(String) 注册驱动,调用 HikariConfig 对象的 hikariConfig.setDriverClassName("org.mariadb.jdbc.Driver"); 即可
JDBC 的使用的更多相关文章
- Java数据库连接技术——JDBC
		
大家好,今天我们学习了Java如何连接数据库.之前学过.net语言的数据库操作,感觉就是一通百通,大同小异. JDBC是Java数据库连接技术的简称,提供连接各种常用数据库的能力. JDBC API ...
 - 玩转spring boot——结合AngularJs和JDBC
		
参考官方例子:http://spring.io/guides/gs/relational-data-access/ 一.项目准备 在建立mysql数据库后新建表“t_order” ; -- ----- ...
 - [原创]java使用JDBC向MySQL数据库批次插入10W条数据测试效率
		
使用JDBC连接MySQL数据库进行数据插入的时候,特别是大批量数据连续插入(100000),如何提高效率呢?在JDBC编程接口中Statement 有两个方法特别值得注意:通过使用addBatch( ...
 - JDBC MySQL 多表关联查询查询
		
public static void main(String[] args) throws Exception{ Class.forName("com.mysql.jdbc.Driver&q ...
 - JDBC增加删除修改
		
一.配置程序--让我们程序能找到数据库的驱动jar包 1.把.jar文件复制到项目中去,整合的时候方便. 2.在eclipse项目右击"构建路径"--"配置构建路径&qu ...
 - JDBC简介
		
jdbc连接数据库的四个对象 DriverManager 驱动类 DriverManager.registerDriver(new com.mysql.jdbc.Driver());不建议使用 ...
 - JDBC Tutorials: Commit or Rollback transaction in finally block
		
http://skeletoncoder.blogspot.com/2006/10/jdbc-tutorials-commit-or-rollback.html JDBC Tutorials: Com ...
 - FineReport如何用JDBC连接阿里云ADS数据库
		
在使用FineReport连接阿里云的ADS(AnalyticDB)数据库,很多时候在测试连接时就失败了.此时,该如何连接ADS数据库呢? 我们只需要手动将连接ads数据库需要使用到的jar放置到%F ...
 - JDBC基础
		
今天看了看JDBC(Java DataBase Connectivity)总结一下 关于JDBC 加载JDBC驱动 建立数据库连接 创建一个Statement或者PreparedStatement 获 ...
 - Spring学习记录(十四)---JDBC基本操作
		
先看一些定义: 在Spring JDBC模块中,所有的类可以被分到四个单独的包:1.core即核心包,它包含了JDBC的核心功能.此包内有很多重要的类,包括:JdbcTemplate类.SimpleJ ...
 
随机推荐
- oracle备份恢复
			
1.oracle文件备份恢复 /etc/oraInst.loc /etc/oratab /home/oracle 家目录 /oracle 安装目录 /usr/local/bin/dbhome /usr ...
 - 读REDIS数据结构
			
一.DICT 主要有两个问题: 1.散列冲突,解决办法是拉链法 typedef struct dictEntry { void *key; union { void *val; uint64_t u6 ...
 - hdu-1754 I Hate It---线段树模板题
			
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1754 题目大意: 求区间最大值+单点修改 解题思路: 直接套用模板即可 #include<bi ...
 - BZOJ4066:简单题(K-D Tree)
			
Description 你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作: 命令 参数限制 内容 1 x y A 1<=x,y<=N,A是正整数 ...
 - 【luogu P3369 【模板】普通平衡树(Treap/SBT)】 题解 pb_ds
			
我永远都爱STL ! 我爱PB_DS ! #include <iostream> #include <cstdio> #include <ext/pb_ds/tree_p ...
 - jdbc连接各种数据库字符串
			
oracle driverClass:oracle.jdbc.driver.OracleDriver url:jdbc:oracle:thin:@127.0.0.1:1521:dbname mysql ...
 - 【题解】洛谷P1006传纸条
			
链接 https://www.luogu.org/problemnew/show/P1006 日常牢骚 过年前最后一节课上完了坐标DP 也接触了一点区间DP(noi1995石子合并)下次做做看看吧 老 ...
 - Trident中 FixedBatchSpout分析
			
FixedBatchSpout 继承自 IBatchSpout IBatchSpout 方法 public interface IBatchSpout extends Serializable { v ...
 - Python—面向对象 封装03
			
接着上面的一篇继续往下: 如何隐藏 在python中用双下划线开头的方式将属性隐藏起来(设置成私有的) class A: __x = 1 # _A__x = 1 def __init__(self, ...
 - AngularJS显示一个简单表格
			
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...