MySQL 系列(二)Jdbc
MySQL 系列(二)Jdbc
一、Jdbc 基本操作
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import org.junit.Test;
public class TestJdbc {
@Test
public void run1() throws Exception{
//1、注册驱动
Class.forName("com.mysql.jdbc.Driver");
//DriverManager.registerDriver(new Driver());
//2、获取连接
//DriverManager 管理一组 jdbc 的操作
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");
//3、编写sql
String sql="select * from users where name=?";
//4、创建语句执行者
PreparedStatement st = conn.prepareStatement(sql);
//5、设置参数
st.setString(1, "aaaa");
//6、执行sql
ResultSet rs = st.executeQuery();
//7、处理结果
while(rs.next()){
System.out.println(rs.getString("id") + "=>" + rs.getString("name"));
}
//8、释放资源.
rs.close();
st.close();
conn.close();
}
}
补充:将类加载到内存中方法:
Class.forName("全限定名");//包名 + 类名 com.mysql.jdbc.Driver
类名.class
对象.getClass()
二、MySQL API
2.1 DriverManager.getConnection()
管理一组 jdbc 的操作
2.2 Connection 接口
常用方法:
(了解)Statement createStatement(): 获取普通的语句执行者,会出现sql注入
☆PreparedStatement prepareStatement(String sql): 获取预编译语句执行者
(了解)CallableStatement prepareCall(String sql): 获取调用存储过程的语句执行者
(了解)setAuotCommit(false): 手动开户事务
(了解)Commit(): 提交事务
(了解)rollback(): 事务回滚
2.3 PreparedStatement 预编译的语句执行者 接口
父类 Statement
语句执行者 接口 有注入
- setString(int 第几个?号, object)
- setInt(int 第几个?号, object)
- setObject(int 第几个?号, object)
- execute(sql): 执行 sql 语句,查询返回结果集,cud 返回受影响的行数
- executeQuery(sql): 执行 r 语句,返回值:结果集
- executeUpdate(): 执行 cud 语句,返回值:影响的行数
2.4 ResultSet 接口: 结果集
next(): 判断是否有下一条记录,若有返回true且将光标移动到下一行,若没有则返回false。光标一开始处于第一条记录的上面。
getString(int|string): 若参数为int: 第几列,若参数为 string: 列名(字段名) getString getInt getObject
2.5 实例,对 jdbc 进行简单的封闭
第一步:创建 jdbc.properties 文件
driverClass=com.mysql.jdbc.Driver
url=jdbc\:mysql\://localhost\:3306/test
user=root
password=root
第二步:创建 jdbcUtils.java 文件
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ResourceBundle;
public class jdbcUtils {
static final String DRIVERCLASS, URL, USER, PASSWORD;
//静态代码块,加载代码时运行,只执行一次人
static {
ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
DRIVERCLASS = bundle.getString("driverClass");
URL = bundle.getString("url");
USER = bundle.getString("user");
PASSWORD = bundle.getString("password");
System.out.println(DRIVERCLASS);
}
static {
//连接驱动
try {
Class.forName(DRIVERCLASS);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
//建立连接
return DriverManager.getConnection(URL, USER, PASSWORD);
}
public static void closeResource(Connection conn, Statement st, ResultSet rs) {
closeResultSet(rs);
closeStatement(st);
closeConn(conn);
}
/**
* 释放连接
* @param conn
*/
public static void closeConn(Connection conn) {
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
conn = null;
}
}
/**
* 释放语句执行者
* @param st
*/
public static void closeStatement(Statement st) {
if(st != null) {
try {
st.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
st = null;
}
}
/**
* 释放结果集
* @param rs
*/
public static void closeResultSet(ResultSet rs) {
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
rs = null;
}
}
}
第三步:测试
import org.junit.Test;
public class jdbcUtils {
@Test
public void run2() {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = jdbcUtils.getConnection();
//创建 sql
String sql = "insert into users (name) values (?)";
//获取语句执行者
st = conn.prepareStatement(sql);
//设置参数
st.setString(1, "sss");
//执行 sql
int i = st.executeUpdate();
//处理结果
if(i == 1) {
System.out.println("success");
} else {
System.out.println("fail");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭连接资源
jdbcUtils.closeResource(conn, st, rs);
}
}
}
补充:properties 配置文件读取:
常见配置文件格式有 properties
和xml
两种,properties
文件读取方式如下:
import java.util.ResourceBundle;
public class TestProperties {
@Test
public void read() throws Exception{
//①获取 ResourceBundle 对象
ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
//①通过 ResourceBundle 对象获取配置信息
String driverClass = bundle.getString("driverClass");
}
}
三、连接池
使用 jdbc 时,每次操作都需要获取连接(创建),用完之后把连接释放(销毁),通过连接池来优化。
3.1 自定义连接池
实现一个自定义的最简单连接池
import java.sql.Connection;
import java.sql.SQLException;
import java.util.LinkedList;
/**
* 最简单的连接池
*/
public class MyDataSource {
//LinkedList 增删快,查询慢
static LinkedList<Connection> pool = new LinkedList<>();
//初始化连接池,放入3个连接
static {
for(int i = 0; i< 3; i++) {
try {
Connection conn = jdbcUtils.getConnection();
pool.addLast(conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//获取连接
public static Connection getConnection() {
if(pool.isEmpty()) {
for(int i = 0; i< 3; i++) {
try {
Connection conn = jdbcUtils.getConnection();
pool.addLast(conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
System.out.println("获取连接");
return pool.removeFirst();
}
//归还连接
public static void addBack(Connection conn) {
System.out.println("已经归还连接");
pool.addLast(conn);
}
}
增强方法
继承/实现
装饰者模式(静态代理)
装饰者和被装饰者实现同一个接口或者继承同一个类
装饰者中要有被装饰者的引用
对需要的增强的方法进行加强
对不需要的方法调用原来的方法
动态代理
增强连接池,实现 conn.close() 归还连接池:
第一步:修改 MyDataSource.java 中 getConnection() 方法的返回值
System.out.println("获取连接");
return new ConnectionWrap(pool.removeFirst(), pool);
第二步:新建 ConnectionWrap.java 对 Connection 的 close() 方法进行增强
import java.sql.*;
import java.util.LinkedList;
public class ConnectionWrap implements Connection {
//连接池
private LinkedList pool;
private Connection conn;
public ConnectionWrap(Connection conn) {
this.conn = conn;
}
public ConnectionWrap(Connection conn, LinkedList pool) {
this.conn = conn;
this.pool = pool;
}
@Override
//修改close方法为归还连接池
public void close() throws SQLException {
this.pool.addLast(this.conn);
System.out.println("连接已经归还!");
}
@Override
//不用增强的方法调用原来的方法
public Statement createStatement() throws SQLException {
return conn.createStatement();
}
@Override
//不用增强的方法调用原来的方法
public PreparedStatement prepareStatement(String sql) throws SQLException {
return conn.prepareStatement(sql);
}
//...
}
第三步:测试
import org.junit.Test;
public class TestJdbc {
@Test
public void run3() throws Exception{
MyDataSource dataSource = new MyDataSource();
ConnectionWrap conn = (ConnectionWrap) dataSource.getConnection();
conn.close();
//获取连接
//连接已经归还!
}
}
3.2 dbcp连接池
第一步:导入 jar 包
commons-dbcp-1.4.jar
commons-pool-1.5.6.jar
第二步:新建 src/main/resources/jdcp.properties 配置文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
username=root
password=root
第三步:dbcp-api
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import org.junit.Test;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.Properties;
public class TestJdbc {
@Test
public void dbcp() throws Exception{
//方法一:
/*BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("root");*/
//方法二:
Properties prop = new Properties();
/*prop.setProperty("driverClassName", "com.mysql.jdbc.Driver");
prop.setProperty("url", "jdbc:mysql://localhost:3306/test");
prop.setProperty("username", "root");
prop.setProperty("password", "root");*/
prop.load(new FileInputStream("src/main/resources/jdcp.properties"));
BasicDataSource dataSource = (BasicDataSource) new BasicDataSourceFactory().createDataSource(prop);
//1、获得连接:
Connection conn = dataSource.getConnection();
//2、编写SQL语句.
String sql = "insert into users values (null, ?, null)";
//3、预编译SQL:
PreparedStatement st = conn.prepareStatement(sql);
//4、设置参数:
st.setString(1, "Tom");
//5、执行SQL
st.execute();
//6、关闭连接
st.close();
conn.close();
}
}
3.3 c3p0连接池(能自动回收空闲连接的功能)
第一步:导入 jar 包 c3p0-0.9.1.2.jar
第二步:c3p0 默认到 src/main/resources/c3p0.properties 读取配置文件
c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql://localhost:3306/test
c3p0.user=root
c3p0.password=root
或 c3p0 默认到 src/main/resources/c3p0-config.xml 读取配置文件
<c3p0-config>
<!-- 默认配置,如果没有指定则使用这个配置 -->
<default-config>
<!-- 基本配置 -->
<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="checkoutTimeout">30000</property>
<property name="idleConnectionTestPeriod">30</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property>
</default-config>
<!-- 命名的配置 -->
<named-config name="name">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/xxxx</property>
<property name="user">root</property>
<property name="password">1234</property>
<!-- 如果池中数据连接不够时一次增长多少个 -->
<property name="acquireIncrement">5</property>
<property name="initialPoolSize">20</property>
<property name="minPoolSize">10</property>
<property name="maxPoolSize">40</property>
<property name="maxStatements">20</property>
<property name="maxStatementsPerConnection">5</property>
</named-config>
</c3p0-config>
第三步:c3p0-api
import org.junit.Test;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
public class TestJdbc {
@Test
public void c3p0() throws Exception {
//默认到 src/main/resources/c3p0.properties 读取配置文件
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//使用命名的配置,若找不到就使用默认的配置
//ComboPooledDataSource dataSource = new ComboPooledDataSource("name");
/*dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUser("root");
dataSource.setPassword("root");*/
//1、获得连接:
Connection conn = dataSource.getConnection();
//2、编写SQL语句.
String sql = "insert into users values (null, ?, null)";
//3、预编译SQL:
PreparedStatement st = conn.prepareStatement(sql);
//4、设置参数:
st.setString(1, "Tom2");
//5、执行SQL
st.execute();
//6、关闭连接
st.close();
conn.close();
}
}
dbutils
DBUtils 封装了对 JDBC 的操作,简化了 JDBC 操作。
Dbutils 三个核心功能介绍:
QueryRunner
提供对 sql 语句操作的 APIResultSetHandler
接口,用于定义 select 操作后,怎样封装结果集DbUtils
工具类,定义了关闭资源与事务处理的方法
QueryRunner
QueryRunner(DataSource ds)
提供数据源(连接池),DBUtils底层自动维护连接connectionupdate(String sql, Object... params)
执行更新数据query(String sql, ResultSetHandler<T> rsh, Object... params)
执行查询
ResultSetHandler
结果集 | 说明 |
---|---|
ArrayHandler | 将结果集中的第一条记录封装到一个Object[]数组中,数组中的每一个元素就是这条记录中的每一个字段的值 |
ArrayListHandler | 将结果集中的每一条记录都封装到一个Object[]数组中,将这些数组在封装到List集合中。 |
BeanHandler | 将结果集中第一条记录封装到一个指定的javaBean中。 |
BeanListHandler | 将结果集中每一条记录封装到指定的javaBean中,将这些javaBean在封装到List集合中 |
ColumnListHandler | 将结果集中指定的列的字段值,封装到一个List集合中 |
KeyedHandler | 将结果集中每一条记录封装到Map<String,Object>,在将这个map集合做为另一个Map的value,另一个Map集合的key是指定的字段的值。 |
MapHandler | 将结果集中第一条记录封装到了Map<String,Object>集合中,key就是字段名称,value就是字段值 |
MapListHandler | 将结果集中每一条记录封装到了Map<String,Object>集合中,key就是字段名称,value就是字段值,在将这些Map封装到List集合中。 |
ScalarHandler | 它是用于单数据,返回五long值。例如select count(*) from 表操作。 |
DbUtils
closeQuietly(Connection conn)
关闭连接,如果有异常 try 后不抛commitAndCloseQuietly(Connection conn)
提交并关闭连接rollbackAndCloseQuietly(Connection conn)
回滚并关闭连接
例子:
import com.herolei.bean.Users;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ArrayHandler;
import org.apache.commons.dbutils.handlers.ArrayListHandler;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
public class TestJdbc {
//1、获取连接池
ComboPooledDataSource dataSource = null;
//2、构造方法QueryRunner(),底层创建连接,创建语句执行者,释放资源
QueryRunner qr = null;
@Before
public void setUp() {
dataSource = new ComboPooledDataSource();
qr = new QueryRunner(dataSource);
}
@Test
public void update() throws Exception {
//3、编写SQL语句.
String sql = "insert into users values (null, ?, null)";
//4、执行sql
qr.update(sql, "Tom4"); //cud操作
//qr.query(sql, "Tom3"); //r操作
}
@Test
//将结果集中的第一条记录封装到一个Object[]数组中,数组中的每一个元素就是这条记录中的每一个字段的值
public void arrayHandler() throws Exception {
String sql = "select * from users";
Object[] query = qr.query(sql, new ArrayHandler());
for (Object obj: query) {
System.out.println(obj);
}
}
@Test
//将结果集中的每一条记录都封装到一个Object[]数组中,将这些数组在封装到List集合中
public void arrayListHandler() throws Exception {
String sql = "select * from users";
List<Object[]> list = qr.query(sql, new ArrayListHandler());
for (Object[] obj: list) {
System.out.println(Arrays.toString(obj));
}
}
@Test
//将结果集中第一条记录封装到一个指定的javaBean中
public void beanHandler() throws Exception {
String sql = "select * from users where id = 19";
Users user = (Users) qr.query(sql, new BeanHandler(Users.class));
System.out.println(user);
}
@Test
//将结果集中每一条记录封装到指定的javaBean中,将这些javaBean在封装到List集合中
public void beanListHandler() throws Exception {
String sql = "select * from users";
List<Users> list = (List<Users>) qr.query(sql, new BeanListHandler(Users.class));
for(Users user: list) {
System.out.println(user);
}
}
}
每天用心记录一点点。内容也许不重要,但习惯很重要!
MySQL 系列(二)Jdbc的更多相关文章
- 一生挚友redo log、binlog《死磕MySQL系列 二》
系列文章 原来一条select语句在MySQL是这样执行的<死磕MySQL系列 一> 一生挚友redo log.binlog<死磕MySQL系列 二> 前言 咔咔闲谈 上期根据 ...
- mysql系列二、mysql内部执行过程
向MySQL发送一个请求的时候,MySQL到底做了什么 客户端发送一条查询给服务器. 服务器先检查查询缓存,如果命中了缓存,则立刻返回存储在缓存中的结果.否则进入下一阶段. 服务器端进行SQL解析.预 ...
- Mysql系列二:Mysql 开发标准规范
原文链接:http://www.cnblogs.com/liulei-LL/p/7729983.html 一.表设计 1. 库名.表名.字段名使用小写字母,“_”分割. 2. 库名.表名.字段名不超过 ...
- MySQL系列(二)--MySQL存储引擎
影响数据库性能的因素: 1.硬件环境:CPU.内存.存盘IO.网卡流量等 2.存储引擎的选择 3.数据库参数配置(影响最大) 4.数据库结构设计和SQL语句 MySQL采用插件式存储引擎,可以自行选择 ...
- MySQL系列(一)--基础知识(转载)
安装就不说了,网上多得是,我的MySQL是8.0版本,可以参考:CentOS7安装MySQL8.0图文教程和MySQL8.0本地访问设置为远程访问权限 我的MySQL安装在阿里云上面,阿里云向外暴露端 ...
- MySQL强人“锁”难《死磕MySQL系列 三》
系列文章 一.原来一条select语句在MySQL是这样执行的<死磕MySQL系列 一> 二.一生挚友redo log.binlog<死磕MySQL系列 二> 前言 最近数据库 ...
- S 锁与 X 锁的爱恨情仇《死磕MySQL系列 四》
系列文章 一.原来一条select语句在MySQL是这样执行的<死磕MySQL系列 一> 二.一生挚友redo log.binlog<死磕MySQL系列 二> 三.MySQL强 ...
- 如何选择普通索引和唯一索引《死磕MySQL系列 五》
系列文章 一.原来一条select语句在MySQL是这样执行的<死磕MySQL系列 一> 二.一生挚友redo log.binlog<死磕MySQL系列 二> 三.MySQL强 ...
- 五分钟,让你明白MySQL是怎么选择索引《死磕MySQL系列 六》
系列文章 二.一生挚友redo log.binlog<死磕MySQL系列 二> 三.MySQL强人"锁"难<死磕MySQL系列 三> 四.S 锁与 X 锁的 ...
- 无法复现的“慢”SQL《死磕MySQL系列 八》
系列文章 四.S 锁与 X 锁的爱恨情仇<死磕MySQL系列 四> 五.如何选择普通索引和唯一索引<死磕MySQL系列 五> 六.五分钟,让你明白MySQL是怎么选择索引< ...
随机推荐
- UOJ117. 欧拉回路【欧拉回路模板题】
LINK 题目大意 就是让你对有向图和无向图分别求欧拉回路 非常的模板,但是由于UOJ上毒瘤群众太多了 所以你必须加上一个小优化 就是每次访问过一个边就把它删掉 有点像Dinic的当前弧优化的感觉 注 ...
- YAML文件格式入门
YAML快速入门 https://www.jianshu.com/p/97222440cd08 https://yaml.org/spec/1.2/spec.pdf http://nodeca.git ...
- jdbc-DAO的实现
什么是 DAO DAO(Data Access Object)是一个数据访问接口,夹在业务逻辑与数据库资源中间. 在核心J2EE模式中是这样介绍DAO模式的:为了建立一个健壮的J2EE应用,应该将所有 ...
- USB学习笔记-协议
一.USB设备枚举过程 1.复位从设备使其设备地址为02.先从设备发送读取设备描述符的命令(只读取一次,即使端点0的最大包长小于18字节)3.设备返回设备描述符4.主机返回0长度确认数据包给到设备5. ...
- Java多线程编程核心技术,第六章
1,饿汉模式/单例模式,一开始就新建一个静态变量,后面用getInstance()都是同一个变量 2,懒汉模式/单例模式,在getInstance()才会new一个对象,在第一个有了后不会继续创建 3 ...
- Linux环境安装jdk10
一. 下载jdk 下载方式一:直接在linux上下载 wget --no-check-certificate --no-cookies --header "Cookie: oraclelic ...
- php 的两个扩展 memcache 和 memcachd
今天绕了很大弯子, 因为自己写的php的memcache类. 于是出现了下面问题 在本地测试好好的, 线上就出了问题 原因是线上使用的是memcache, 我本地使用的是memcached 区别参考网 ...
- 学习OCI编程
转自:http://kulong0105.blog.163.com/blog/static/174406191201162145944574/ 最近公司做的一个项目,要处理海量数据,数据是存放在Ora ...
- ROS注册级别LEVEL0-6,原来使用GRE通道是不要钱滴
GRE通道是没有个数限制的.如果只做一个分公司的PPTP,L2TP,等等,也是不用钱滴. 跑OSPF就不行了,必须要给钱.
- Linux内核优化(未注释)
Nginx代理服务内核优化 # Kernel sysctl configuration file for Red Hat Linux # # For binary values, 0 is disab ...