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提供不可靠,无连接的数据报传送服务. 不可靠:它不能保 ...
随机推荐
- react组件传值(props[只读属性]) 函数组件
组件间传值,在React中是通过只读属性 props 来完成数据传递的. props:接受任意的入参,并返回用于描述页面展示内容的 React 元素. function Cmp1(props) { r ...
- INFINI Easysearch 与兆芯完成产品兼容互认证
近日,极限科技旗下软件产品 INFINI Easysearch 搜索引擎软件 V1.0 与兆芯完成兼容性测试,功能与稳定性良好,并获得兆芯产品兼容互认证书. 此次兼容适配基于银河麒麟高级服务器操作系统 ...
- 基于 Easysearch kNN 搭建即时图片搜索服务
环境准备 启动 Easysearch 服务: # Make sure your vm.max_map_count meets the requirement sudo sysctl -w vm.max ...
- win10无线网卡不会自动连接
usb接口的网卡.win10无线网卡不会自动连接. 解决方法: 第一步:在控制面板\网络和 Internet\网络连接中,禁用再启用一次无线网络. 第二步:在 控制面板\硬件和声音\电源选项\选择电源 ...
- 百度面试:如何用Redis实现限流?
高并发系统有三大特征:限流.缓存和熔断,所以限流已经成为当下系统开发中必备的功能了.那么,什么是限流?如何实现限流?使用 Redis 能不能实现限流?接下来我们一起来看. 1.什么是限流? 限流是指在 ...
- Django路由层、视图层及模板层
Django路由层 URL配置(URLconf)就像Django所支撑网站的目录.它的本质是URL与要为该URL调用的视图函数之间的映射表; 你就是以这种方式告诉Django,对于客户端发来的某个UR ...
- Docker入门系列之四:Docker镜像
在本文中,您将学习如何加快Docker构建周期并创建轻量级镜像.遵循之前的文章中的食物隐喻,我们将沙拉隐喻为Docker镜像,同时减少Docker镜像的数量. 在本系列的第3部分中,我们介绍了十几个D ...
- 支付宝spi接口设计验签和返回结果加签注意点,支付宝使用JSONObject对象
支付宝spi接口设计验签和返回结果加签注意点,支付宝使用JSONObject对象 SPI 三方服务接入指南https://opendocs.alipay.com/isv/spiforisv 服务端实现 ...
- nacos v2.2 k8s部署启动报错:nacos server did not start because dumpservice bean construction failure. errMsg102, errllsg dataSource or tableName is null
背景 最近搭建个nacos环境,用的镜像是2.2版本的,yaml如下: nacos-conf apiVersion: v1 kind: ConfigMap metadata: name: nacos- ...
- Linux常用耗资源命令汇总
在Linux中,以下命令可能在处理大量数据或复杂操作时比较消耗资源.一般来说,涉及大量数据处理.计算或者I/O操作的命令会比较耗费系统资源. 注意:所有命令资源消耗都是相对的,基于文件的处理量来展 ...