JDBC详解学习笔记
JDBC简介
架构时——没有什么是加一层解决不了的,如果有,就再加一层。
如tomcat集群上面的Nginx,Nginx集群上面的LVS.
JDBC是数据库驱动的接口规范,是SUN公司未来简化开发人员对数据库的统一操作而提供的一个规范。即Java数据库连接,(Java Database Connectivity,简称JDBC)。
这些规范有具体的数据库厂商去实现,而开发人员只需要掌握JDBC接口操作即可。
没有JDBC时:

通过JDBC时:


JDBC操作步骤——贾琏欲执事
口诀:贾琏欲执事——加连预执释
- 加载驱动
- 连接数据库
- 创建预编译语句
- 执行sql
- 释放资源

| url键值对 | 描述 |
|---|---|
| useUnicode=true | 支持中文编码 |
| characterEncoding=utf8 | 设置字符集编码为utf8 |
| useSSL=true | 使用安全连接 |
JDBC对象解析
oracle没有数据库概念,一个模式就是一个库




statement对象



JDBC工具类示例
public class JDBCTest {
public static void main(String[] args) {
//查询、插入展示
select();
insert();
}
public static void select() {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JDBCUtil.getConnection();
st = conn.createStatement();
String sql = "select * from user where 1=1";
rs = st.executeQuery(sql);
while (rs.next()) {
//参数为字段名
System.out.println(rs.getString("name"));
}
} catch (Exception throwables) {
throwables.printStackTrace();
} finally {
JDBCUtil.release(rs, st, conn);
}
}
public static void insert() {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JDBCUtil.getConnection();
st = conn.createStatement();
String sql = "insert into user(`name`,age)values ('安安',1)";
int i = st.executeUpdate(sql);
if (i > 0) {
System.out.println("插入成功");
}
} catch (Exception throwables) {
throwables.printStackTrace();
} finally {
JDBCUtil.release(rs, st, conn);
}
}
}
//JDBC工具类,返回的Connection相当于一个数据库操作对象,可以用于事务等处理
public class JDBCUtil {
private static String URL = null;
private static String USERNAME = null;
private static String PASSWORD = null;
private static String DIRVIER = null;
static {
//通过classloader去获取配置文件的输入流
InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("db.properties");
//再创建properties对象去load输入流
Properties properties = new Properties();
try {
properties.load(is);
} catch (IOException e) {
e.printStackTrace();
}
URL = properties.getProperty("roy.mysql.url");
USERNAME = properties.getProperty("roy.mysql.username");
PASSWORD = properties.getProperty("roy.mysql.password");
DIRVIER = properties.getProperty("roy.mysql.driver");
try {
Class.forName(DIRVIER);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(URL, USERNAME, PASSWORD);
}
public static void release(ResultSet rs, Statement st, Connection conn) {
try {
if (rs != null) {
rs.close();
}
if (st != null) {
st.close();
}
if (conn != null) {
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
roy.mysql.url=jdbc:mysql://localhost:3306/mybatis_plus?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
roy.mysql.username=root
roy.mysql.password=123456
roy.mysql.driver=com.mysql.cj.jdbc.Driver
#注意properties文件就是String类型的键值对,因此不需要再加""双引号
sql注入
所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。
我们永远不要信任用户的输入,我们必须认定用户输入的数据都是不安全的,我们都需要对用户输入的数据进行过滤处理。


PreparedStatement——防止sql注入
PreparedStatement可以防止sql注入,其防止sql注入的本质是PreparedStatement会把传进来的参数当做字符,假如其中存在转义符如''引号这种,会被直接转义处理;且因为预编译所以效率更高。
DB中执行的SQL为
select file from file where name = '\'test\' or 1=1'
把整个参数用引号包起来,并把参数中的引号作为转义字符,从而避免了参数也作为条件的一部分
示例
public class PreparedStatementTest {
public static void main(String[] args) {
select();
insert("白衣阿风",28);
}
public static void select() {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = JDBCUtil.getConnection();
String sql = "select * from user where 1=1 and `name` =?";
st = conn.prepareStatement(sql);
st.setString(1,"艾米");
rs = st.executeQuery();
while (rs.next()) {
//参数为字段名
System.out.println(rs.getString("email"));
}
} catch (Exception throwables) {
throwables.printStackTrace();
} finally {
JDBCUtil.release(rs, st, conn);
}
}
public static void insert(String name,Integer age) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = JDBCUtil.getConnection();
String sql = "insert into user(`name`,age)values (?,?)";
st = conn.prepareStatement(sql);
st.setString(1,name);
st.setInt(2,age);
int i = st.executeUpdate();
if (i > 0) {
System.out.println("插入成功");
}
} catch (Exception throwables) {
throwables.printStackTrace();
} finally {
JDBCUtil.release(rs, st, conn);
}
}
}
Idea连接数据库





JDBC事务

代码示例
public class TranscationTest {
public static void main(String[] args) {
transcation("艾米哈珀","哈米国王",new BigDecimal("1500000"));
}
public static void transcation(String seller,String buyer, BigDecimal money) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = JDBCUtil.getConnection();
//关闭事务自动提交,这时候表示自动开启事务
conn.setAutoCommit(false);
String sql1 = "update t_bank_account set money=money+? where `name`=?";
st = conn.prepareStatement(sql1);
st.setBigDecimal(1,money);
st.setString(2,seller);
int i = st.executeUpdate();
//测试事务异常
// System.out.println(1/0);
String sql2 = "update t_bank_account set money=money -? where `name`=?";
st = conn.prepareStatement(sql2);
st.setBigDecimal(1,money);
st.setString(2,buyer);
int j = st.executeUpdate();
if (j > 0 && i > 0) {
System.out.println("交易成功");
}
conn.commit();
} catch (Exception throwables) {
try {
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
throwables.printStackTrace();
} finally {
JDBCUtil.release(rs, st, conn);
}
}
}
数据库连接池——池化技术
池化技术的出现在于每次创建连接和释放连接都非常的耗费资源,现实场景中,我们更好的处理方法是通过池化技术来优化和提高这种每次都要创建释放资源的事情,就像我们的工厂生产产品或者银行对外提供服务,工厂不能有产品要生产才招一个临时工,生产完就解雇掉;银行不能每次要处理业务就开个门或者说开个窗口,处理好了就把处理窗口关闭了,两者在现实中我们都能观察到:工厂是有一定数量的稳定工人的,而银行的对外业务窗口也是稳定的,这就是池化技术。
数据库连接池的本质是实现一个DataSource接口。

开源数据源实现
- DBCP
- C3P0
- Druid(德鲁伊)阿里巴巴开源
使用了这些数据库连接池后,我们在项目开发中就不需要编写连接数据库的代码了。

DBCP及C3P0示例
maven依赖
<!-- dbcp连接池依赖,commons-dbcp内部已经依赖了commons-pool-->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.5.4</version>
</dependency>
<!-- c3p0连接依赖,c3p0内部已经依赖了mchange-commons-java-->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
dbcp配置文件——dbcp.properties
driverClassName=com.mysql.cj.jdbc.Driver
#url
url=jdbc:mysql://localhost:3306/mybatis_plus?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
#用户名
username=root
#密码
password=123456
#初试连接数
initialSize=30
#最大活跃数
maxTotal=30
#最大idle数
maxIdle=10
#最小idle数
minIdle=5
#最长等待时间(毫秒)
maxWaitMillis=1000
#程序中的连接不使用后是否被连接池回收(该版本要使用removeAbandonedOnMaintenance和removeAbandonedOnBorrow)
#removeAbandoned=true
removeAbandonedOnMaintenance=true
removeAbandonedOnBorrow=true
#连接在所指定的秒数内未使用才会被删除(秒)(为配合测试程序才配置为1秒)
removeAbandonedTimeout=1
c3p0配置文件——c3p0-config.xml
<c3p0-config>
<!-- 使用默认的配置读取连接池对象 -->
<default-config>
<!-- 连接参数 -->
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/mybatis_plus?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8</property>
<property name="user">root</property>
<property name="password">123456</property>
<!-- 连接池参数 -->
<!--初始化申请的连接数量-->
<property name="initialPoolSize">5</property>
<!--最大的连接数量-->
<property name="maxPoolSize">10</property>
<!--超时时间-->
<property name="checkoutTimeout">3000</property>
</default-config>
<!-- 其他如oracle、mysql等的配置,要使用时只需要指定要加载的配置名问参数,不传则使用默认配置-->
<named-config name="mysql">
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 连接池参数 -->
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">8</property>
<property name="checkoutTimeout">1000</property>
</named-config>
</c3p0-config>
public class C3P0Util {
private static DataSource dataSource = null;
static {
//通过classloader去获取配置文件的输入流
try {
dataSource = new ComboPooledDataSource();
//不指定配置名称则读取默认的c3p0配置
//xml文件不需要读取成流便能读取文件
// dataSource = new ComboPooledDataSource("mysql");
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
public static void release(ResultSet rs, Statement st, Connection conn) {
try {
if (rs != null) {
rs.close();
}
if (st != null) {
st.close();
}
if (conn != null) {
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class DBCPUtil {
private static DataSource dataSource = null;
static {
//通过classloader去获取配置文件的输入流
InputStream is = DBCPUtil.class.getClassLoader().getResourceAsStream("dbcp.properties");
//再创建properties对象去load输入流
Properties properties = new Properties();
//Properties文件注意要加载流,否则读不到文件会报错如下
//org.apache.commons.dbcp.SQLNestedException: Cannot create JDBC driver of class '' for connect URL 'null'
try {
properties.load(is);
} catch (IOException e) {
e.printStackTrace();
}
try {
dataSource = BasicDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
public static void release(ResultSet rs, Statement st, Connection conn) {
try {
if (rs != null) {
rs.close();
}
if (st != null) {
st.close();
}
if (conn != null) {
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class ConnectionPoolTest {
public static void main(String[] args) {
c3p0();
dbcp();
}
public static void c3p0() {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = C3P0Util.getConnection();
st = conn.createStatement();
String sql = "select * from user where 1=1";
rs = st.executeQuery(sql);
while (rs.next()) {
//参数为字段名
System.out.println(rs.getString("name"));
}
} catch (Exception throwables) {
throwables.printStackTrace();
} finally {
JDBCUtil.release(rs, st, conn);
}
}
public static void dbcp() {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = DBCPUtil.getConnection();
st = conn.createStatement();
String sql = "insert into user(`name`,age)values ('安安啊',1)";
int i = st.executeUpdate(sql);
if (i > 0) {
System.out.println("插入成功");
}
} catch (Exception throwables) {
throwables.printStackTrace();
} finally {
JDBCUtil.release(rs, st, conn);
}
}
}
参考文献
[狂神MySQL基础](
JDBC详解学习笔记的更多相关文章
- TCP/IP详解学习笔记
TCP/IP详解学习笔记(1)-基本概念 TCP/IP详解学习笔记(2)-数据链路层 TCP/IP详解学习笔记(3)-IP协议,ARP协议,RARP协议 TCP/IP详解学习笔记(4)-ICMP协议, ...
- TCP/IP详解学习笔记 这位仁兄写得太好了
TCP/IP详解学习笔记(1)-基本概念 为什么会有TCP/IP协议 在世界上各地,各种各样的电脑运行着各自不同的操作系统为大家服务,这些电脑在表达同一种信息的时候所使用的方法是千差万别.就好像圣 ...
- TCP/IP详解学习笔记- 概述
TCP/IP详解学习笔记(1)-- 概述1.TCP/IP的分层结构 网络协议通常分不同层次进行开发,每一层分别负责不同的同信功能.TCP/IP通常被认为是一个四层协议系统. 如图所 ...
- TCP-IP详解学习笔记2
TCP-IP详解学习笔记2 链路层 链路层的目的是为IP模块发送和接收IP数据报: TCP/IP支持多种不同的链路层,依赖于使用网络硬件类型:有线局域网(以太网,城域网(MAN),有线语音网络).无线 ...
- TCP-IP详解学习笔记1
TCP-IP详解学习笔记1 网关可以在互不相关的网络之间提供翻译功能: 体系结构: 协议和物理实现,实际上是一组设计决策. TCP/IP协议族允许计算机,智能手机,嵌入式设备之间通信: TCP/IP是 ...
- TCP/IP详解学习笔记 这位仁兄写得太好了.(转载)
TCP/IP详解学习笔记 这位仁兄写得太好了 TCP/IP详解学习笔记 这位仁兄写得太好了. http://blog.csdn.net/goodboy1881/category/20444 ...
- 【转】TCP/IP详解学习笔记(二)
TCP/IP详解学习笔记(5)-IP选路,动态选路,和一些细节 1.静态IP选路 1.1.一个简单的路由表 选路是IP层最重要的一个功能之一.前面的部分已经简单的讲过路由器是通过何种规则来根据IP数据 ...
- 【转】TCP/IP详解学习笔记(一)
TCP/IP详解学习笔记 这位仁兄写得太好了. http://blog.csdn.net/goodboy1881/category/204448.aspx TCP/IP详解学习笔记(13)-T ...
- 孙鑫视频VC++深入详解学习笔记
孙鑫视频VC++深入详解学习笔记 VC++深入详解学习笔记 Lesson1: Windows程序运行原理及程序编写流程 Lesson2: 掌握C++基本语法 Lesson3: MFC框架程序剖析 Le ...
- TCP/IP详解学习笔记(3)-- IP:网际协议
1.概述 IP是TCP/IP协议族中最为核心的协议.所有的TCP,UDP,ICMP,IGMP数据都以IP数据报格式传输. IP提供不可靠,无连接的数据报传送服务. 不可靠:它不能保 ...
随机推荐
- jquery的树状菜单
<body> <ul> <li>一级菜单 <ol> <li ...
- BLP 模型
公号:Rand_cs BLP 模型 本篇文章是调研了许多资料后对 BLP 模型的一个总结 MLS,Multi-level Security,主要关心的是数据机密性 D. Elliott Bell 和 ...
- kettle从入门到精通 第六十一课 ETL之kettle 任务调度器,轻松使用xxl-job调用kettle中的job和trans
1.大家都知道kettle设计的job流程文件有个缺点:只能设置简单的定时任务,无法设置复杂的如支持cron表达式的job. 今天给大家分享一个使用xxl-job调度carte的流程文件的示例.整个调 ...
- #9134.反转eehniy
blog 题面 yinhee 去面试 Google 总裁. 面试官给他了一个长度为 \(n\) 的 \(01\) 串. 面试官给他以下两种操作是的这个序列前 \(n-m\) 个数字与后 \(n-m\) ...
- docker综合应用
1.容器资源限制 官网文档 https://docs.docker.com/config/containers/resource_constraints/ 2.docker内存限制 -m或者--mem ...
- hdfs修复块
磁盘满了一次,导致hdfs的很多块变成一个副本 看一下副本信息 执行 hdfs fsck / 1007个块少于3个副本一下 而且 hbase的regionsever启动报错 File /apps/h ...
- 【vue】利用输入框搜索过滤来选择列表
方法1 <div id="app"> <input type="text" @input="handleInput()" ...
- FPGA对EEPROM驱动控制(I2C协议)
本文摘要:本文首先对I2C协议的通信模式和AT24C16-EEPROM芯片时序控制进行分析和理解,设计了一个i2c通信方案.人为按下写操作按键后,FPGA(Altera EP4CE10)对EEPROM ...
- 下载 Linux 内核的脚本
介绍 在 类UNIX 环境下运行比较好(基于wget) 包括了 2.6 ~ 4.x 内核的地址. 5.x 因为 还在更新因此不做记录. 脚本下载地址: https://files.cnblogs.co ...
- Linux服务器从头配置
安装配置jdk 下载 jdk jdk-8u171-linux-x64.tar.gz 将该压缩包放到/usr/local/jdk目录下然后解压(jdk目录需要自己手动创建) tar zxvf jdk-8 ...