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提供不可靠,无连接的数据报传送服务. 不可靠:它不能保 ...
随机推荐
- minos 0 前(废)言(话)
- 首发公号:Rand_cs minos 0 前(废)言(话) 从今天开始开启一个新的系列,讲述虚拟化的那些事儿.时隔上次发文又隔了好几个月了,主要是平时工作比较忙,没太多时间精力维护博客之类的. 前 ...
- OOP第一阶段题集总结
一.前言 知识点:数组,字符串的使用,链表,hashmap,泛型的使用,正则表达式的使用,类的设计,类与类之间的关系,单一职责. 题量:题目数量为5+4+3,数量适中,其中都是前几题较简单,最后一题较 ...
- 企业级私有仓库Harbor
仓库的概念也就是用于存储,docker仓库用于存储镜像. 镜像构建完成后,很容易可以在宿主机上运行,但是如果要在其他服务器上运行,则需要考虑镜像的分发,存储的问题. 共有/私有/仓库 Docker R ...
- 使用Git命令从本地上传到码云
Gitee创建仓库内没有内容 本地: 初始化Git仓库:git init 提交文件到暂存区:git add . //. 表示提交所有文件 提交文件到工作区:git commit -m "此次 ...
- Python 安装 matlabengin 时遇到报错:setup.py install is deprecated. !! 以及 Cannot update time stamp of directory 'dist\matlabengine.egg-info' 的解决方案
目录 Python 安装 matlabengin 时遇到报错:setup.py install is deprecated. !! 以及 Cannot update time stamp of dir ...
- Java面试知识点(六)hashmap深度理解
1.hashmap 的数据结构 要知道 hashmap 是什么,首先要搞清楚它的数据结构,在 java 编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用 ...
- mysql多表删除指定记录
在Mysql4.0之后,mysql开始支持跨表delete. Mysql可以在一个sql语句中同时删除多表记录,也可以根据多个表之间的关系来删除某一个表中的记录. 假定我们有两张表:Product表和 ...
- Wireshark抓包分析理解DHCP协议及工作流程
一.DHCP简介 DHCP(Dynamic Host Configuration Protocol)动态主机配置协议,前身是BOOTP协议.在大型局域网中,需要给很多主机配置地址信息,如果采用传统 ...
- 多核处理器与MP架构
多核处理器也称片上多核处理器(Chip Multi-Processor,CMP). 多核处理器的流行 多核出现前,商业化处理器都致力于单核处理器的发展,其性能已经发挥到极致,仅仅提高单核芯片的速度会产 ...
- Oracle自动化编译无效对象
问题描述:使用存储过程的方式对oracle数据库的无效对象,如视图或者同义词进行定期的编译,让他变成一个有效的对象,加上定时任务可以实现自动化的处理.同时在数据库内部创建一个记录表,用来记录被编译过的 ...