案例1-通过jdbc完成单表的curd操作
jdbc:
java操作数据库.jdbc是oracle公司指定的一套规范(一套接口)
驱动:jdbc的实现类.由数据库厂商提供.
我们就可以通过一套规范操作不同的数据库了(多态)
jdbc作用:
连接数据库
发送sql语句
处理结果
jdbc操作步骤:★
1.数据库和表
2.创建一个项目
3.导入驱动jar包
4.编码:
注册驱动
获取连接
编写sql
创建预编译的语句执行者
设置参数
执行sql
处理结果
释放资源
初始化数据库和表:
CREATE DATABASE day07;
USE day07;
create table category(
cid varchar(20) primary key,
cname varchar(20)
);
insert into category values('c001','电器');
insert into category values('c002','服饰');
insert into category values('c003','化妆品');
insert into category values('c004','书籍');
IDE打开之后
1.修改字符集 utf-8
2.新建 java项目
3.使用的jdk为自己的jdk 不用使用内置
使用junit单元测试
要求:
1.方法是public void xxx(){}
2.在方法上添加 @Test
3.在@Test 按下 ctrl+1(快速锁定错误)
4.在方法上右键 run as -->junit 就可以执行方法了.
jdbc-api详解:
所有的包 都是 java.sql 或者 javax.sql
DriverManager:管理了一组jdbc的操作 类
常用方法:
了解:注册驱动
static void registerDriver(Driver driver) :
通过查看 com.mysql.jdbc.Driver的源码 有如下代码
static {
try {
java.sql.DriverManager.registerDriver(new Driver());//这段代码我们已经写过
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
驱动注册了两次.我们只需要将静态代码块执行一次,类被加载到内存中会执行静态代码块,并且只执行一次.
现在只需要将类加载到内存中即可:
方式1:
★Class.forName("全限定名");//包名+类名 com.mysql.jdbc.Driver
方式2:
类名.class;
方式3:
对象.getClass();
掌握:获取连接
static Connection getConnection(String url, String user, String password)
参数1:告诉我们连接什么类型的数据库及连接那个数据库
协议:数据库类型:子协议 参数
mysql: jdbc:mysql://localhost:3306/数据库名称
oracle: jdbc:oracle:thin@localhost:1521@实例
参数2:账户名 root
参数3:密码
(了解)Driver:java.sql 接口 驱动
Connection:连接 接口
常用方法:
获取语句执行者:
(了解)Statement createStatement() :获取普通的语句执行者 会出现sql注入问题
★PreparedStatement prepareStatement(String sql) :获取预编译语句执行者
(了解)CallableStatement prepareCall(String sql):获取调用存储过程的语句执行者
了解:
setAutoCommit(false) :手动开启事务
commit():提交事务
rollback():事务回滚
Statement:语句执行者 接口
PreparedStatement:预编译语句执行者 接口
常用方法:
设置参数:
setXxx(int 第几个问号,Object 实际参数);
常见的方法:
setInt
setString
setObject
执行sql:
ResultSet executeQuery() :执行 r 语句 返回值:结果集
int executeUpdate() :执行cud 语句 返回值:影响的行数
ResultSet:结果集 接口
执行查询语句之后返回的结果
常用方法:
boolean next():判断是否有下一条记录,若有返回true且将光标移到下一行,若没有呢则返回false
光标一开始处于第一条记录的上面
获取具体内容
getXxx(int|string)
若参数为int :第几列
若参数为string:列名(字段名)
例如:
获取cname的内容可以通过
getString(2)
getString("cname")
常用方法:
getInt
getString 也可以获取int值
getObject 可以获取任意
常见的配置文件格式:
1.properties
里面内容的格式 key=value
2.xml
若我们的配置文件为properties,并且放在src目录下.
我们可以通过 ResourceBundle工具快速获取里面的配置信息
使用步骤:
1.获取ResourceBundle 对象:
static ResourceBundle getBundle("文件名称不带后缀名")
2.通过ResourceBundle 对象获取配置信息
String getString(String key) :通过执行key获取指定的value
案例
@Test
public void test2() throws Exception {
//注册驱动
//DriverManager.registerDriver(new Driver());
//为什么不用DriverManager.registerDriver(new Driver());?因为Driver内部又注册了一次。
Class.forName("com.mysql.jdbc.Driver");
//获取连接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day07", "root", "123456");
//创建执行语句预编译对象
PreparedStatement ps = conn.prepareStatement("select * from category");
//设置参数
//执行sql,获取结果集
ResultSet rs = ps.executeQuery();
while (rs.next()) {
String cid = rs.getString("cid");
String cname = rs.getString("cname");
System.out.println("test2---cid="+cid+",cname="+cname);
}
//释放资源:关闭connection resultset ps
rs.close();
ps.close();
conn.close();
}
封装 注册驱动+获取连接 和释放资源的操作:
@Test
public void test3() throws Exception {
//注册驱动 +获取连接
Connection conn = Jdbc1Utils.getConnection();
//创建执行语句预编译对象
PreparedStatement ps = conn.prepareStatement("select * from category");
//设置参数
//执行sql,获取结果集
ResultSet rs = ps.executeQuery();
while (rs.next()) {
String cid = rs.getString("cid");
String cname = rs.getString("cname");
System.out.println("test3---cid="+cid+",cname="+cname);
}
//释放资源:关闭connection resultset ps
Jdbc1Utils.closeResource(rs, ps, conn);
}
public class Jdbc1Utils {
public static Connection getConnection() throws Exception {
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获取连接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day07", "root", "123456");
return conn;
}
public static void closeResource(ResultSet rs,Statement st,Connection conn) {
closeResultSet(rs);
closeStatement(st);
closeConnection(conn);
}
public static void closeResultSet(ResultSet rs) {
if(null!=rs) {
try {
rs.close();
} catch (Exception e) {
e.printStackTrace();
}
rs=null;
}
}
public static void closeStatement(Statement st) {
if(null!=st) {
try {
st.close();
} catch (Exception e) {
e.printStackTrace();
}
st=null;
}
}
public static void closeConnection(Connection conn) {
if(null!=conn) {
try {
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
conn=null;
}
}
}
优化: 数据库的信息我们应该写到配置文件里面,这样改的话比较方便
@Test
public void test4() throws Exception {
Connection conn = JdbcUtils.getConnection();
//创建执行语句预编译对象
PreparedStatement ps = conn.prepareStatement("select * from category");
//设置参数
//执行sql,获取结果集
ResultSet rs = ps.executeQuery();
while (rs.next()) {
String cid = rs.getString("cid");
String cname = rs.getString("cname");
System.out.println("test4---cid="+cid+",cname="+cname);
}
//释放资源:关闭connection resultset ps
JdbcUtils.closeResource(rs, ps, conn);
}
public class JdbcUtils {
public static final String DRIVERCLASS;
public static final String URL;
public static final String USER;
public static final String PASSWORD;
//jdbc
// static {
// ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
// DRIVERCLASS = bundle.getString("driverClass");
// URL = bundle.getString("url");
// USER = bundle.getString("user");
// PASSWORD = bundle.getString("password");
// }
//c3p0
// static {
// ResourceBundle bundle = ResourceBundle.getBundle("c3p0");
// DRIVERCLASS = bundle.getString("c3p0.driverClass");
// URL = bundle.getString("c3p0.jdbcUrl");
// USER = bundle.getString("c3p0.user");
// PASSWORD = bundle.getString("c3p0.password");
// }
//dbcp
static {
ResourceBundle bundle = ResourceBundle.getBundle("dbcp");
DRIVERCLASS = bundle.getString("driverClassName");
URL = bundle.getString("url");
USER = bundle.getString("username");
PASSWORD = bundle.getString("password");
}
static {
//注册驱动
try {
Class.forName(DRIVERCLASS);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws Exception {
//获取连接
Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
return conn;
}
public static void closeResource(ResultSet rs,Statement st,Connection conn) {
closeResultSet(rs);
closeStatement(st);
closeConnection(conn);
}
public static void closeResultSet(ResultSet rs) {
if(null!=rs) {
try {
rs.close();
} catch (Exception e) {
e.printStackTrace();
}
rs=null;
}
}
public static void closeStatement(Statement st) {
if(null!=st) {
try {
st.close();
} catch (Exception e) {
e.printStackTrace();
}
st=null;
}
}
public static void closeConnection(Connection conn) {
if(null!=conn) {
try {
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
conn=null;
}
}
}
增:
@Test
public void test5() throws Exception {
Connection conn = JdbcUtils.getConnection();
//创建执行语句预编译对象
PreparedStatement ps = conn.prepareStatement("insert into category values(?,?)");
//设置参数
ps.setObject(1, "c007");
ps.setString(2, "小米手机");
int executeUpdate = ps.executeUpdate();
System.out.println("test5---executeUpdate="+executeUpdate);
//释放资源:关闭connection resultset ps
JdbcUtils.closeResource(null, ps, conn);
}
改:
@Test
public void test6() throws Exception {
Connection conn = JdbcUtils.getConnection();
//创建执行语句预编译对象
PreparedStatement ps = conn.prepareStatement("update category set cname=? where cid=?");
//设置参数
ps.setObject(1, "小米9");
ps.setString(2, "c008");
int executeUpdate = ps.executeUpdate();
System.out.println("test6---executeUpdate="+executeUpdate);
//释放资源:关闭connection resultset ps
JdbcUtils.closeResource(null, ps, conn);
}
删:
@Test
public void f7() throws Exception {
//获取连接
Connection conn = JdbcUtils.getConnection();
//语句执行者
PreparedStatement ps = conn.prepareStatement("delete from category where cid=?");
//执行
ps.setString(1, "c007");
int executeUpdate = ps.executeUpdate();
System.out.println("test7---executeUpdate="+executeUpdate);
//释放资源
//释放资源:关闭connection resultset ps
JdbcUtils.closeResource(null, ps, conn);
}
案例2-通过连接池(数据源)优化我们的操作.
需求:
使用jdbc的时候,没操作一次都需要获取连接(创建)用完之后把连接释放掉了(销毁),通过连接池来优化curd操作.
技术分析:
连接池
连接池概述:
管理数据库的连接,
作用:
提高项目的性能.
就是在连接池初始化的时候存入一定数量的连接,用的时候通过方法获取,不用的时候归还连接即可.
所有的连接池必须实现一个接口 javax.sql.DataSource接口
获取连接方法:
Connection getConnection()
归还连接的方法就是以前的释放资源的方法.调用connection.close();
自定义一个连接池(理解思想)
常用连接池:
DBCP
C3P0
增强方法
1.继承
2.装饰者模式(静态代理)
3.动态代理
装饰者模式:★★★
使用步骤:
1.装饰者和被装饰者实现同一个接口或者继承同一个类
2.装饰者中要有被装饰者的引用
3.对需要增强的方法进行加强
4.对不需要加强的方法调用原来方法
常用的连接池:
DBCP:(理解)
apache组织
使用步骤:
1.导入jar包(commons-dbcp-1.4.jar和commons-pool-1.5.6.jar)
2.使用api
a.硬编码
//创建连接池
BasicDataSource ds = new BasicDataSource();
//配置信息
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql:///day07");
ds.setUsername("root");
ds.setPassword("1234");
b.配置文件
实现编写一个properties文件
//存放配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("src/dbcp.properties"));
//设置
//prop.setProperty("driverClassName", "com.mysql.jdbc.Driver");
//创建连接池
DataSource ds = new BasicDataSourceFactory().createDataSource(prop);
C3P0:(★)
hibernate和spring使用
有自动回收空闲连接的功能.
使用步骤:
1.导入jar包(c3p0-0.9.1.2.jar)
2.使用api
a.硬编码(不推荐)
new ComboPooledDataSource()
b.配置文件
配置文件的名称:c3p0.properties 或者 c3p0-config.xml
配置文件的路径:src下
编码只需要一句话
new ComboPooledDataSource()//使用默认的配置
new ComboPooledDataSource(String configName)//使用命名的配置 若配置的名字找不到,使用默认的配置
自定义简易连接池
public static void main(String[] args) {
MyDateSource ds = new MyDateSource();
Connection conn = ds.getConnection();
// Connection conn = MyDateSource.getConnection();
System.out.println(conn);
MyDateSource.addBack(conn);
}
public class MyDateSource {
public static LinkedList<Connection> pooList=new LinkedList<Connection>();
//创建3个连接,并放入集合中
static {
for (int i = 0; i < 3; i++) {
try {
Connection conn = JdbcUtils.getConnection();
pooList.addLast(conn);
} catch (Exception e) {
e.printStackTrace();
}
}
}
//取任意一个连接
public static Connection getConnection() {
//取之前判断连接池是否为空,为空则新增3个
if(pooList.isEmpty()) {
for (int i = 0; i < 3; i++) {
try {
Connection conn = JdbcUtils.getConnection();
pooList.addLast(conn);
} catch (Exception e) {
e.printStackTrace();
}
}
}
return pooList.removeFirst();
}
//归还连接
public static void addBack(Connection conn) {
pooList.addLast(conn);
}
}
Connection 装饰者模式+简易连接池(各连接池jar的原理)
Connection 装饰者模式:
public class ConnectionWrap implements Connection {
private Connection conn;
private LinkedList<Connection> list;
public ConnectionWrap(Connection conn,LinkedList<Connection> list) {
this.conn=conn;
this.list=list;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return conn.unwrap(iface);
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public Statement createStatement() throws SQLException {
return conn.createStatement();
}
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
return conn.prepareStatement(sql);
}
@Override
public void close() throws SQLException {
System.out.println("close前---"+list.size());
list.addLast(this);
System.out.println("close后---"+list.size());
}
...
}
自定义简易连接池:
public class MyDateSource {
public static LinkedList<Connection> pooList=new LinkedList<Connection>();
//创建3个连接,并放入集合中
static {
for (int i = 0; i < 3; i++) {
try {
Connection conn = JdbcUtils.getConnection();
pooList.addLast(conn);
} catch (Exception e) {
e.printStackTrace();
}
}
}
//取任意一个连接
public static Connection getConnection() {
//取之前判断连接池是否为空,为空则新增3个
if(pooList.isEmpty()) {
for (int i = 0; i < 3; i++) {
try {
Connection conn = JdbcUtils.getConnection();
pooList.addLast(conn);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Connection conn = pooList.removeFirst();
ConnectionWrap wrap = new ConnectionWrap(conn, pooList);
return wrap;
}
//归还连接
public static void addBack(Connection conn) {
pooList.addLast(conn);
}
}
测试:
public static void main(String[] args) throws SQLException {
MyDateSource ds = new MyDateSource();
Connection conn = ds.getConnection();
System.out.println(conn);
conn.close();
}
dbcp连接池
- 需要2个jar: commons-dbcp-1.4.jar+commons-pool-1.5.6.jar
@Test
public void f1() throws SQLException {
//创建数据源
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql:///day07");
ds.setUsername("root");
ds.setPassword("123456");
//获取连接
Connection conn = ds.getConnection();
PreparedStatement ps = conn.prepareStatement("insert into category values(?,?)");
ps.setString(1, "c008");
ps.setString(2, "苹果12");
//执行
int executeUpdate = ps.executeUpdate();
JdbcUtils.closeResource(null, ps, conn);
}
@Test
public void f2() throws Exception {
Properties properties=new Properties();
properties.load(new FileInputStream("src/dbcp.properties"));
//创建数据源
DataSource ds = BasicDataSourceFactory.createDataSource(properties);
//获取连接
Connection conn = ds.getConnection();
PreparedStatement ps = conn.prepareStatement("insert into category values(?,?)");
ps.setString(1, "c009");
ps.setString(2, "苹果13");
//执行
int executeUpdate = ps.executeUpdate();
JdbcUtils.closeResource(null, ps, conn);
}
dbcp.properties:
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///day07
username=root
password=123456
c3p0连接池
c3p0-0.9.1.2.jar
@Test
public void f1() throws Exception {
ComboPooledDataSource ds=new ComboPooledDataSource();
//如果默认是c3p0.properties,下面的4行可以省略
ds.setDriverClass("com.mysql.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql:///day07");
ds.setUser("root");
ds.setPassword("123456");
//获取连接
Connection conn = ds.getConnection();
PreparedStatement ps = conn.prepareStatement("insert into category values(?,?)");
ps.setString(1, "c010");
ps.setString(2, "苹果10");
//执行
int executeUpdate = ps.executeUpdate();
JdbcUtils.closeResource(null, ps, conn);
}
封装数据库参数:
@Test
public void f2() throws Exception {
ComboPooledDataSource ds=new ComboPooledDataSource("c3p0.properties");
//获取连接
Connection conn = ds.getConnection();
PreparedStatement ps = conn.prepareStatement("insert into category values(?,?)");
ps.setString(1, "c011");
ps.setString(2, "苹果11");
//执行
int executeUpdate = ps.executeUpdate();
JdbcUtils.closeResource(null, ps, conn);
}
案例3-使用dbutils完成curd操作
dbutils:
是apache组织的一个工具类,jdbc的框架,更方便我们使用
使用步骤:
1.导入jar包(commons-dbutils-1.4.jar)
2.创建一个queryrunner类
queryrunner作用:操作sql语句
构造方法:
new QueryRunner(Datasource ds);
3.编写sql
4.执行sql
query(..):执行r操作
update(...):执行cud操作
核心类或接口
QueryRunner:类名
作用:操作sql语句
构造器:
new QueryRunner(Datasource ds);
注意:
底层帮我们创建连接,创建语句执行者 ,释放资源.
常用方法:
query(..):
update(..):
DbUtils:释放资源,控制事务 类
closeQuietly(conn):内部处理了异常
commitAndClose(Connection conn):提交事务并释放连接
....
ResultSetHandler:封装结果集 接口
ArrayHandler, ArrayListHandler, BeanHandler, BeanListHandler, ColumnListHandler, KeyedHandler, MapHandler, MapListHandler, ScalarHandler
带有List表示结果是集合,不带list表示结果是对象(相等于取集合的第一条数据)
(了解)ArrayHandler, 将查询结果的第一条记录封装成数组,返回
(了解)ArrayListHandler, 将查询结果的每一条记录封装成数组,将每一个数组放入list中返回
★★BeanHandler, 将查询结果的第一条记录封装成指定的bean对象,返回
★★BeanListHandler, 将查询结果的每一条记录封装成指定的bean对象,将每一个bean对象放入list中 返回.
(了解)ColumnListHandler, 将查询结果的指定一列放入list中返回
(了解)MapHandler, 将查询结果的第一条记录封装成map,字段名作为key,值为value 返回
★MapListHandler, 将查询结果的每一条记录封装map集合,将每一个map集合放入list中返回
★ScalarHandler,针对于聚合函数 例如:count(*) 返回的是一个Long值
BeanHandler
QueryRunner qr = new QueryRunner(C3p0DataSourceUtils.getDataSource());
String sql="select * from category";
Category category = qr.query(sql, new BeanHandler<>(Category.class));
System.out.println(category);
BeanListHandler
QueryRunner qr = new QueryRunner(C3p0DataSourceUtils.getDataSource());
String sql="select * from category";
List<Category> list = qr.query(sql, new BeanListHandler<>(Category.class));
for (Category category : list) {
System.out.println(category);
}
ScalarHandler
QueryRunner qr = new QueryRunner(C3p0DataSourceUtils.getDataSource());
String sql="select count(cid) from category";
Object Object = qr.query(sql, new ScalarHandler());
System.out.println(Object.getClass().getName());
System.out.println(Object);
Long count = (Long) qr.query(sql, new ScalarHandler());
System.out.println(count);
ArrayHandler
QueryRunner qr = new QueryRunner(C3p0DataSourceUtils.getDataSource());
String sql="select * from category";
Object[] result = qr.query(sql, new ArrayHandler());
System.out.println(Arrays.toString(result))
ArrayListHandler
QueryRunner qr = new QueryRunner(C3p0DataSourceUtils.getDataSource());
String sql="select * from category";
List<Object[]> list = qr.query(sql, new ArrayListHandler());
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
MapHandler
QueryRunner qr = new QueryRunner(C3p0DataSourceUtils.getDataSource());
String sql="select * from category";
Map<String, Object> map = qr.query(sql, new MapHandler());
System.out.println(map);
MapListHandler
QueryRunner qr = new QueryRunner(C3p0DataSourceUtils.getDataSource());
String sql="select * from category";
List<Map<String,Object>> list = qr.query(sql, new MapListHandler());
for (Map<String,Object> map : list) {
System.out.println(map);
}
ColumnListHandler
QueryRunner qr = new QueryRunner(C3p0DataSourceUtils.getDataSource());
String sql="select * from category";
//无参默认第一列的值
List<Object> list = qr.query(sql, new ColumnListHandler("cname"));
for (Object object : list) {
System.out.println(object);
System.out.println(object.getClass().getName());
}
KeyedHandler
QueryRunner qr = new QueryRunner(C3p0DataSourceUtils.getDataSource());
String sql="select * from category";
//无参默认第一列的值
Map<Object, Map<String, Object>> map = qr.query(sql, new KeyedHandler());
System.out.println(map);
Set<Object> keySet = map.keySet();
for (Object cid : keySet) {
//key:cid value:record
System.out.println(cid+"---"+map.get(cid));
}