jdbc是Sun公司抽取出来的一套操纵数据库的接口规范, 由不同的数据库服务器厂商按照接口规范实现
结论: JDBC就是java连接数据库的桥梁
1、使用相对简单
开发者只需会调用JDBC接口中的方法即可,使用简单;
面向接口编程
2、访问接口实现与开发解耦
底层实现交给具体的数据库厂商来完成,与开发者解耦;
开发者只需按照流程开发即可,无需关注与数据库交互细节;
3、移植性好
对于不同 的数据库,开发者使用同一套Java代码,进行少量的修改就可以访问其他JDBC支持的数据库
一致性相对较好
# JDBC相关包
1) java.sql:`JDBC访问数据库的基础包`,在JavaSE中的包。如:java.sql.Connection
2) javax.sql:`JDBC访问数据库的扩展包` (x表示extension,扩展`)
3) `数据库的驱动`,各大数据库厂商来实现。如:MySQL的驱动:com.mysql.jdbc.Driver
# JDBC四个核心对象
DriverManager(类):`数据库驱动管理类`。
作用: 1) 注册驱动;
2) 创建java代码和数据库之间的连接,即获取Connection接口;
Connection(接口):`建立数据库连接的一个接口`。
作用:建立数据库和java代码之间的连接。表示与数据库创建的连接对象。
Statement(接口):`数据库操作接口`,向数据库发送sql语句。执行SQL语句的对象。
PreparedStatement(接口):继承Statement (`解决安全隐患问题,比如sql注入的问题`)。
ResultSet(接口):`是结果集或一张虚拟表`。Statement 发送sql语句,返回的结果 封装在 ResultSet 中。
由DriverManager注册驱动程序;
创建和数据库的连接对象Connection;
由客户端发送SQL语句给服务器执行,SQL语句封装成Statement对象;
查询到的结果集封装成ResultSet对象;
在客户端可以从ResultSet中取出数据,处理结果集;
释放资源,关闭连接对象;
通过DriverManager类注册驱动程序。
static void registerDriver(Driver driver);
@Test
public void test1() throws SQLException {
//1. 显式注册方式
DriverManager.registerDriver(new Driver());
//2.获取所有注册的驱动 发现mysql的驱动类注册的2次
Enumeration<java.sql.Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()){
System.out.println(drivers.nextElement().toString());
}
}
使用显式注册驱动,数据库驱动被注册了2次,是什么原因呢?
查看源码:
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
// Register ourselves with the DriverManager
static {
try {
//在类被加载的时候,静态代码块就注册了一次了
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
因为Mysql驱动类Driver在被加载时,静态代码块中已经注册了一次,
如果显式调DriverManager.registerDriver()方法会导致驱动类注册2次,浪费内存。
通过获得Driver的Class对象
Class.forName(“com.mysql.jdbc.Driver”);
@Test
public void test2() throws SQLException, ClassNotFoundException {
//1. 隐式注册方式
Class.forName("com.mysql.jdbc.Driver");
//2.获取所有注册的驱动 发现mysql的驱动类注册的1次
Enumeration<java.sql.Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()){
System.out.println(drivers.nextElement().toString());
}
}
java.sql.DriverManager类中有如下方法获取数据库连接
static Connection getConnection(String url, String user, String password);
参数说明:
1. String url :连接数据库的URL,用于说明连接数据库的位置
2. String user :数据库的账号
3. String password :数据库的密码
连接数据库的URL:
URL是sun公司与数据库厂商之间的一种协议
格式 : 协议:子协议:/IP:端口号 数据库
示例: jdbc:mysql://localhost:3306/数据库名称
IDEA与数据库的SQL交互要使用Statement对象完成,
在java.sql.Connection接口中有如下方法获取到Statement对象:
Statement的API
// 获取发送sql语句的对象
Statement createStatement() throws SQLException;
// 执行增删改操作
int executeUpdate(String sql) throws SQLException;
// 执行查询操作
ResultSet executeQuery(String sql) throws SQLException;
JDBC通过statement执行查询的sql后,会将查询的结果封装到ResultSet的对象中
ResultSet的原理
1. ResultSet内部有一个指针, 刚开始记录开始位置;
2. 调用next方法, ResultSet内部指针会移动到下一行数据;
3. 我们可以通过ResultSet得到一行数据 getXxx得到某列数据;
例如:
ResultSet rs = stm.executeQuery(select);
rs.next() // 存在下一条记录,返回true,否则返回false
id int
name varchar
score double
rs.getXxx获取字段值
rs.getInt(1); 或者rs.getInt(“id”); ------>1
rs.getString(2);或者rs.getString(“name”); ------>张三
rs.getDouble(3);或者rs.getDouble(“score”);------>80
ResultSet获取数据的API是有规律的,在get后面加数据类型
1. jdbc查询使用步骤?
1) 注册驱动
2) 获取连接对象
3) 获取发送sql的对象Statement;
4) 发送sql,获取结果集; ResultSet rs= stm.executeQuery(sql);
5) 解析结果集,获取数据
6) 关闭资源,释放连接(3个close)
2. ResultSet如何获取数据?
1) 调用next()方法获取某一行的记录;
2) 通过getXxx(字段索引位);getXxx(字段名称);
@Test
public void test7() throws ClassNotFoundException, SQLException {
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接对象
String url="jdbc:mysql://127.0.0.1:3306/daname";
String user="root";
String pwd="1234";
Connection conn = DriverManager.getConnection(url, user, pwd);
//3.获取发送sql的对象
Statement sm = conn.createStatement();
//4.发送查询sql语句,获取结果集
String select="select * from user";
ResultSet rs = sm.executeQuery(select);
//5.解析结果集,获取数据
while (rs.next()){
int id = rs.getInt(1);
String name = rs.getString("username");
String password = rs.getString(3);
System.out.println(id+name+password);
}
//6 释放资源
rs.close();
sm.close();
conn.close();
}
问题
之前的jdbc代码存在大量重复
数据库的用户名、密码等连接参数发生改变,对我们后期的维护是非常繁琐的
解决方案
把jdbc操作数据库的一些常用的方法抽出来,放到一个外部的工具类中
jdbc.properties文件
将配置文件存储在外部文件中,通过java io读取配置文件,这样既可以实现几种配置管理,又避免了java类因为参数的修改的问题,反复进行编译的问题
##配置参数
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.dburl=jdbc:mysql://127.0.0.1:3306/java127_jdbc01
jdbc.userName=root
jdbc.password=1234
JdbcUtil类
public class JdbcUtil {
private static String driverClass;
private static String dburl;
private static String userName;
private static String password;
//使用静态代码块,注册驱动,只注册一次即可
static {
// 通过Properties load方法
Properties properties = new Properties();
try (InputStream in = JdbcUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");) {
properties.load(in);
//1.初始化连接数据库的4大核心参数
driverClass = properties.getProperty("jdbc.driverClass");
dburl = properties.getProperty("jdbc.dburl");
userName = properties.getProperty("jdbc.userName");
password = properties.getProperty("jdbc.password");
//2.注册驱动
try {
Class.forName(driverClass);
} catch (ClassNotFoundException e) {
System.out.println(e.getMessage());
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取连接对象
*/
public static Connection getConnection() {
//2.获取连接
Connection conn = null;
try {
conn = DriverManager.getConnection(dburl, userName, password);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
/**
* 关闭资源
* @param rs
* @param stm
* @param conn
*/
public static void close(ResultSet rs, Statement stm, Connection conn) {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException e) {
System.out.println("rsError:" + e.getMessage());
}
try {
if (stm != null) {
stm.close();
}
} catch (SQLException e) {
System.out.println("stmError:" + e.getMessage());
}
try {
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
System.out.println("connError:" + e.getMessage());
}
}
}
Connection接口中与事务相关的核心API
// autoCommit为 true:自动提交 flase:手动提交
void setAutoCommit(boolean autoCommit) throws SQLException;
// 提交事务
void commit() throws SQLException;
// 回滚事务
void rollback() throws SQLException;
注意:
在jdbc事务操作中,事务的控制都是通过Connection对象完成的,当一个完整的业务操作前,我们首先使用conn.setAutoCommit(false)来设置事务手动提交。
默认情况下是true的,表示自动提交事务,那么一条sql语句就是一个事务,默认提交事务。如果设置为false,那么表示开启事务,所有的sql语句就会都在一个事务中。
当业务操作完成之后,如果整个操作没有问题,我们需要使用conn.commit()来提交事务。当然了,如果出现了异常,我们需要使用conn.rollback()撤销所有的操作,所以出现异常,需要进行事务的回滚。
准备数据
-- demo:转账业务:a给b转账100
# 创建账号表
create table account(
id int primary key auto_increment,
name varchar(20),
money double
);
# 初始化数据
insert into account values (null,'a',1000);
insert into account values (null,'b',1000);
调用自定义JdbcUtil类测试方法完成事务
@Test
public void test8() {
Connection conn = JdbcUtil.getConnection();
Statement stm =null;
try {
//1.设置事务手动提交
conn.setAutoCommit(false);
//2.获取发送sql的对象Statement
stm = conn.createStatement();
//2.a扣款100
String subMoney="update account set money=money-100 where name='a'";
stm.executeUpdate(subMoney);
//b入账100
String toMoney="update account set money=money+100 where name='b'";
stm.executeUpdate(toMoney);
//事务提交
conn.commit();
} catch (SQLException e) {
System.out.println(e.getMessage());
if(conn!=null){
try {
//事务回滚
conn.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JdbcUtil.close(null,stm,conn);
}
}
}
由于没有对用户输入进行充分检查,而SQL又是拼接而成,在用户输入参数时,在参数中添加一些SQL 关键字,达到改变SQL运行结果的目的,也可以完成恶意攻击。
简单来说就是:用户在页面提交数据的时候人为的添加一些特殊字符,使得sql语句的结构发生了变化,最终可以在没有用户名或者密码的情况下进行登录。
调用自定义JdbcUtil类测试方法完成用户登陆
@Test
public void test10() throws SQLException {
Connection conn = JdbcUtil4.getConnection();
//获取发送sql的对象
Statement stm = conn.createStatement();
----------------------------------
正确的用户名 + 密码登陆
/*
String user="张三";
String password="1234";
String loginSql="select * from user where username='"+user+"' and
password='"+password+"'";
*/
//select * from user where username='张三' and password='1234'
----------------------------------
特殊字符拼接【改变原本查询语句的本意】获取信息
//发送登录的sql查询用户信息
String user="xxx' or 1=1 -- ";
String password="xxx";
String loginSql="select * from user where username='"+user+"' and password='"+password+"'";
// 查询变为 select * from user 【得到表中所有数据】
// select * from user where username='xxx' or 1=1 -- ' and password='1234'
----------------------------------
ResultSet rs = stm.executeQuery(loginSql);
if(rs.next()){
String username = rs.getString("username");
String pwd = rs.getString(3);
System.out.println(username+pwd);
System.out.println("恭喜:"+username+"登录成功!");
}else{
System.out.println("您输入的用户名或者密码错误!");
}
//关闭资源
JdbcUtil4.close(rs,stm,conn);
}
PreparedStatement是Statement的子接口,可以防止sql注入问题。
可以通过Connection接口中的**prepareStatement(sql)**方法获得PreparedStatement的对象。
Statement与PreparedStatement的区别
statement 执行 sql不进行预编译,有sql注入的风险
PreparedStatement 执行 sql进行预编译,防止sql注入
步骤1:PreparedStatement pstmt = conn.prepareStatement(sql); //需要事先传递sql模板。如果sql需要参数,使用?进行占位
步骤2:设置参数(执行sql之前)
pstmt.setXxx(int index, 要放入的值)
//根据不同类型的数据进行方法的选择。第一个参数index表示的是?出现的位置。
从1开始计数,有几个问号,就需要传递几个参数
方法的参数说明:
第一个参数:int index 表示的是问号出现的位置。 问号是从1开始计数
第二个参数:给问号的位置传入的值
步骤3:执行(不需要在传递sql了)
pstmt.executeQuery(); //执行select
pstmt.executeUpdate(); //执行insert,delete,update
再次调用自定义JdbcUtil类测试方法完成用户登陆【防sql注入】
使用PreparedStatement实现用户登录
@Test
public void testLogin() throws SQLException {
Connection conn = JdbcUtil.getConnection();
//1.获取发送sql的预编译对象
String sql = "select * from user where username=? and password=?";
PreparedStatement pstm = conn.prepareStatement(sql);
//2.设置参数
//pstm.setString(1,"liuyan");
pstm.setString(1, "xxx' or 1=1 -- ");
pstm.setString(2, "xxx");
// 3.发送参数,执行sql,获取查询结果集
ResultSet rs = pstm.executeQuery();
System.out.println(rs.getRow());
// 4.关闭资源
JdbcUtil.close(null, pstm, conn);
}
JDBC调用存储过程API
1)获取连接Connection的对象
2)使用连接Connection的对象调用连接Connection的对象接口中的方法获取CallableStatement接口对象
JDBC调用存储过程API
1.获取发送存储过程语句的Statement
• Connection中定义了获取存储过程的Statement方法API;
• CallableStatement prepareCall(String sql) throws SQLException;
• 其中SQL模板格式:String sql="{call 存储过程名(?,?, ...)}";
2.IN入参设置方法
void setString(int parameterIndex, String x) throws SQLException;
• Eg: void setString(int parameterIndex, String x) throws SQLException;
•说明:parameterIndex表示SQL模板中参数索引位,第二个参数是传入的具体值;
3.OUT出参设置
void registerOutParameter(int parameterIndex, int sqlType) throws SQLException;
•说明:第一个参数表示SQL模板中参数索引位,第二个参数表示出参的类型,可使用java.sql.Types类获取指定类型
4.调用存储过程
boolean execute() throws SQLException;
5.获取出参
int getInt(int parameterIndex) throws SQLException;
•说明:paramterIndex表示出参在SQL模板中的索引位;
JDBC 存储过程
delimiter $
CREATE PROCEDURE transfer (
IN fromSub VARCHAR (20),
IN toSub VARCHAR (20),
IN m FLOAT,
OUT flag INT
)
BEGIN
DECLARE
update_line1 INT DEFAULT 0 ; DECLARE
update_line2 INT DEFAULT 0 ; -- 开启事务
START TRANSACTION ; -- fromSub扣款
UPDATE account SET money = money - m WHERE NAME = fromSub ; -- 获取扣款受影响的行数
SELECT row_count() INTO update_line1 ; -- toSub收款
UPDATE account SET money = money + m WHERE NAME = toSub ;
SELECT row_count() INTO update_line2 ;
IF update_line1 > 0 AND update_line2 > 0 THEN
-- 事务提交
COMMIT ;
SET flag = 1 ;
ELSE
-- 事务回滚
ROLLBACK ;
SET flag = 0 ;
END IF;
end$
##调用存储过程
call transfer('tom','rose',500,@flag);
select @flag;
代码演示
public class TransferProcedure {
public static void main(String[] args) throws SQLException {
//1.获取连接对象
Connection conn = JDBCUtil2.getConnection(true);
//2.获取操纵存储过程的预编译对象
String sql="{call transfer(?,?,?,?)}";
CallableStatement cstm = conn.prepareCall(sql);
//3.设置参数
//3.1 设置入参
cstm.setString(1,"a");
cstm.setString(2,"b");
cstm.setFloat(3,100f);
//3.2注册出参
cstm.registerOutParameter(4, Types.INTEGER);
//4.发送参数,执行存储过程
cstm.execute();
//5.获取出参
int flag = cstm.getInt(4);
System.out.println(flag);
//6.关闭资源
JDBCUtil2.close(null,cstm,conn);
}
}
`1、开发中,常使用分层思想
1) 不同的层次结构分配不同的解决过程,各个层次间组成严密的封闭系统
2) 不同层级结构彼此平等
3) 分层的目的是:
a:解耦,就是降低代码之间的依赖关系。
b:可维护性,哪一层出现问题,直接维护哪一层。
c:可扩展性,哪一层需要添加代码,直接添加即可。
d:可重用性,一个方法可以被其它层重复调用。
`2、不同层次,使用不同的包表示
1)com.testdemo.web web层 公司域名倒写。和前端页面直接交互。
2)com.testdemo.service service层。也叫做业务层。专门用来处理业务的,比如事务。
3)com.testdemo.dao dao层。数据处理层。
操作数据库的代码都书写在这一层。直接和数据库交互。
4)com.testdemo.domain/entity/bean/pojo javabean 存放实体类。临时存放数据
5)com.testdemo.utils 存放工具类。
`三层架构好处:
1)各个层,比如web,service,dao层解耦;
2) 提高了代码的复用性;
3)提高了可维护性;
`jdbc属于那一层
dao层(持久层)
在实际开发中,中小型项目都遵循三层架构开发,
# 1. 定义 User实体类
public class User {
private Integer id;
private String userName;
private String password;
//setter and getter and toString()
# 2. 查询结果封装成集合
@Test
public void test5() throws ClassNotFoundException, SQLException {
//1)注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2)获取连接
String url="jdbc:mysql://localhost:3306/dbname";
String user="root";
String pwd="1234";
Connection conn = DriverManager.getConnection(url, user, pwd);
//3)获取发送sql的对象
Statement Statement stm = conn.createStatement();
//4)发送select查询语句
String sql="select * from user"; ResultSet rs = stm.executeQuery(sql);
//5)解析rs结果集,获取数据
ArrayList<User> users = new ArrayList<>();
while (rs.next()){
int id = rs.getInt(1);
String username = rs.getString("username");
String password = rs.getString("password");
User us = new User();
us.setId(id);
us.setUserName(username);
us.setPassword(password);
users.add(us);
}
// users.forEach(u-> System.out.println(u.toString()));
System.out.println(users);
//6)释放资源
rs.close();
stm.close();
conn.close();
}
}
1、conn底层基于tcp/ip,连接非常耗时;
2、每次连接完毕,资源都要释放,性能开销大;
3、连接资源的复用性差;
1、操作数据库都需要创建连接,操作完成还需要关闭连接
2、创建连接和关闭连接需要可能比执行sql需要的时间都长
3、一个网站需要高频繁的访问数据库,如果短时间频繁的访问数据库服务器,
就容易造成服务器的宕 机,即死机。
连接池中保存了一些数据库连接,这些连接是可以重复使用的。节省数据库的资源消耗。
`1.连接池的好处
1)提高了【连接对象的复用性】
2)避免了数据库连接对象反复的创建与销毁带来的【性能开销】
3)提高了【数据库的性能】
4)从客户端角度看【避免了oom】(out of memory error)
`2.连接池的原理
1) 初始化一定数量的数据库连接对象;
2)客户端不需要自己创建连接对象,直接从连接池中获取连接对象,直接使用即可;
3)客户端使用完毕后,归还连接对象到连接池;
javax.sql.DataSource 表示数据库连接池,
DataSource本身只是Sun公司提供的一个接口,没有具体的实现,
它的实现由连接池的数据库厂商去实现。只需要学习这个工具如何使用即可。
public interface DataSource {
Connection getConnection(); }
06)常用的连接池实现组件
德鲁伊Druid连接池:
Druid是阿里巴巴开源平台上的项目,整个项目由数据库连接池、插件框架和SQL解析器组成。
该项目主要是为了扩展JDBC的一些限制,可以让程序员实现一些特殊的需求。
C3P0数据库连接池
是一个开源的JDBC连接池,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有
Hibernate、Spring等。C3P0有自动回收空闲连接功能。
DBCP(DataBase Connection Pool)数据库连接池
是Apache上的一个Java连接池项目。dbcp没有自动回收空闲连接的功能。
C3P0 是一个开源的JDBC连接池,目前spring 和 hibernate框架对C3P0是支持的。
使用c3p0数据库连接池之前,首先需要在资料中找到如下的jar包,加载到项目中。
com.mchange.v2.c3p0.ComboPooledDataSource
类
表示C3P0的连接池对象,常用2种创建连接池的方式
1.无参构造,使用默认配置 ,
2.有参构造,使用命名配置
// 无参构造使用默认配置(使用xml中default-config标签中对应的参数)
public ComboPooledDataSource()
//有参构造使用命名配置(configName:xml中配置的名称,使用xml中named-config标签中对应的参数
public ComboPooledDataSource(String configName)
// 从连接池中取出一个连接
public Connection getConnection() throws SQLException
1.导入jar包 c3p0-0.9.1.2.jar
2.编写 c3p0-config.xml 配置文件,配置对应参数
3.将配置文件放在src目录下
注意事项
C3P0配置文件名称必须为 c3p0-config.xml
C3P0命名配置可以有多个
4. 创建连接池对象`ComboPooledDataSource`,使用默认配置或命名配置
// 1.创建c3p0连接池对象
ComboPooledDataSource dataSource = new ComboPooledDataSource();
5. 从连接池中获取连接对象
// 2.获取连接对象
Connection conn = dataSource.getConnection();
6. 使用连接对象操作数据库,与正常jdbc操纵方式一致
7. 关闭资源,归还连接资源
rs.close();
stm.close();
conn.close(); //将连接对象归还给连接池,并不是关闭连接对象
编写 c3p0-config.xml 配置文件,配置对应参数
2) 在数据源构造器中指定数据库开发环境
//创建c3p0连接池对象,指定数据源名称
ComboPooledDataSource dataSource = new ComboPooledDataSource("dev");
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driverproperty>
<property name="jdbcUrl">jdbc:mysql:///dbnameproperty>
<property name="user">rootproperty>
<property name="password">1234property>
<property name="initialPoolSize">10property>
<property name="maxIdleTime">30property>
<property name="maxPoolSize">100property>
<property name="minPoolSize">10property>
default-config>
<named-config name="dev">
<property name="driverClass">com.mysql.jdbc.Driverproperty>
<property name="jdbcUrl"> jdbc:mysql://127.0.0.1:3306/dbnameproperty>
<property name="user">rootproperty>
<property name="password">1234property>
<property name="initialPoolSize">4property>
named-config>
c3p0-config>
c3p0连接池常用的配置参数说明:
initialPoolSize : 初始连接数 刚创建好连接池的时候准备的连接数量
maxPoolSize : 最大连接数 连接池中最多可以放多少个连接
checkoutTimeout : 最大等待时间 连接池中没有连接时最长等待时间
maxIdleTime : 最大空闲回收时间 连接池中的空闲连接多久没有使用就会回收
Druid是阿里巴巴开发的号称为监控而生的数据库连接池(可以监控访问数据库的性能),Druid是目前最好的数据库连接池。在功能、性能、扩展性方面,都超过其他数据库连接池。Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。如:一年一度的双十一活动,每年春运的抢火车票。
核心类:DruidDataSourceFactory
获取数据源的方法:使用com.alibaba.druid.pool.DruidDataSourceFactory类中的静态方法:
// 创建一个连接池,连接池的参数使用properties中的数据
public static DataSource createDataSource(Properties properties);
1、导包
2、下创建一个properties文件,文件名随意,设置对应参数
Druid连接池在创建的时候需要一个Properties对象来设置参数
Druid连接池的配置文件名称随便,放到src目录或者项目根目录下面。
加载
druid.properties
文件内容。
# 数据库连接参数
url=jdbc:mysql://localhost:3306/dbname
username=root
password=1234
driverClassName=com.mysql.jdbc.Driver
3、加载properties文件的内容到Properties对象中
InputStream in = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
Properties prop = new Properties();
prop.load(in);
4、创建DRUID连接池,使用配置文件中的参数
//使用DruidDataSourceFactory工厂类构建连接池
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
5) 从DRUID连接池中取出连接
//从连接池对象中获取连接对象
Connection conn = dataSource.getConnection();
6) 执行SQL语句
7) 关闭资源,归还连接
rs.close();
stm.close();
conn.close(); //将连接对象归还给连接池
JDBC技术
jdbc:java数据库连接技术
jdbc开发流程:
1、导入数据库厂商提供的jar文件
2、注册驱动
Class.forName("驱动类");//驱动类统一由DriverManager管理
3、连接数据库
Connection con=DriverManager.getConnection("连接数据库的url","登录名","密码");
4、创建给数据库发送sql语句的对象
Statement stmt = con.createStatement();
5、给数据库发送sql语句, 并接收sql执行的结果
int i = stmt.executeUpdate("insert ... / update.... / delete ....");
ResultSet rs = stmt.executeQuery("select .....");
6、处理结果
while(rs.next())//获取结果集的下一行记录。有记录:true
{
int id = rs.getInt("表中字段名");
String name = rs.getString("表中字段名");
......
}
7、关闭资源
rs.close();//关闭结果集
stmt.close();//关闭发送sql的对象
conn.close();//关闭连接
//CRUD:增删改查
//Statement对象存在的弊端: 存在sql注入问题
//解决方案: 使用子接口PreparedStatement (发送sql语句的对象)
//特殊之处:创建对象时需要指定sql语句(功能:预编译sql语句)
//提供的额外功能:占位符 ?
//注册驱动
Class.forName("驱动类");
//连接数据库
Connection con=DriverManager.getConnection("连接数据库的url","登录名","密码");
//创建给数据库发送sql语句的对象
PreparedStatement pstmt = con.prepareStatement("delete from 表名 where id=?");
//给sql语句中的占位符,赋值:
pstmt.setInt(1,100);//给第1个占位符赋值为100
//给数据库发送sql语句, 并接收sql执行的结果
int i = pstmt.executeUpdate();
//关闭资源
rs.close();//关闭结果集
stmt.close();//关闭发送sql的对象
conn.close();//关闭连接
//事务操作
//默认jdbc事务:自动提交
//手动方式: setAutoCommit(false);
//注册驱动
Class.forName("驱动类");
//连接数据库
Connection con=DriverManager.getConnection("连接数据库的url","登录名","密码");
/*设置事务为手动提交*/
con.setAutoCommit(falase);
//创建给数据库发送sql语句的对象
PreparedStatement pstmt = con.prepareStatement("delete from 表名 where id=?");
//给sql语句中的占位符,赋值:
pstmt.setInt(1,100);//给第1个占位符赋值为100
//给数据库发送sql语句, 并接收sql执行的结果
int i = pstmt.executeUpdate();
/* 事务提交 或 事务的回滚 */
if(i>0){
con.commit();
}
//关闭资源
rs.close();//关闭结果集
stmt.close();//关闭发送sql的对象
cone.close();//关闭连接
连接池技术
核心思想:提前创建好一些Connection对象,存放到一个容器中
连接池技术:
C3P0
1、导入C3P0需要的jar文件
2、在src目录下创建:c3p0-config.xml (文件名是固定名称,不能改变)
3、在xml文件中编写配置参数 (驱动、url、用户名、密码, 初始化连接数、....)
4、创建连接池对象
javax.sql.DataSource ds = new ComboPooledDataSource();
Druid
1、导入Druid需要的jar文件
2、在src目录下创建xxx.properties文件(文件名任意)
3、创建Properties对象,加载xxx.properties文件
4、创建连接池对象
javax.sql.DataSource ds = DruidDataSourceFactory.createDateSource(properties对象)
//利用连接池对象,获取一个Connection对象
Connection con = 连接池对象.getConnection();
//创建给数据库发送sql语句的对象
PreparedStatement pstmt = con.prepareStatement("delete from 表名 where id=?");
//给sql语句中的占位符,赋值:
pstmt.setInt(1,100);//给第1个占位符赋值为100
//给数据库发送sql语句, 并接收sql执行的结果
int i = pstmt.executeUpdate();
//关闭资源
rs.close();//关闭结果集
stmt.close();//关闭发送sql的对象
conn.close();//关闭连接(把Connection对象归还到连接池中)
1)jdbc开发流程:
1.注册驱动
Class.forName(驱动类的全限定名称);
2.获取连接对象
conn=DriverManager.getConnection(url,user,pwd);
3.获取发送sql的对象
pstm= conn.prepareStatement(sql模板);//防止sql注入
stm=conn.createStatement();//会有sql注入的问题
CallableStatement cstm=conn.prepareCall("{call 存储过程名称(?,?,...)}");
4.发送参数或者sql
1)发送sql:
executeQuery(sql); // select
executeUpdate(sql);// insert delete update
execute();
2)发送参数
//设置参数
比如:pstm.setXX(参数索引位,值);
executeQuery();
executeUpdate();
5.获取结果
1)返回受影响的行数
2)返回结果集ResultSet
next();//true/false
getXX(字段索引位,从1开始);
getXX(字段名称);
6.释放资源,关闭连接
2)jdbc之事务
jdbc默认事务自动提交;
conn.setAutoCommit(false);//设置事务手动提交
conn.commit();
conn.rollback();
3)连接池
常用的参数:
1)数据库的4大参数‐‐ url driverclass user pwd
2) 初始化大小 最大连接数 最小连接数 等待时间等