JDBC就是用了让JAVA代码能更好的与数据库连接而由sun公司推出的一套java应用程序访问数据库的技术规范。,使用JDBC需要几个步骤,同时对于增删改查也分为两种不同的操作,为了避免设置拼串时可能出现异常,使用preparedStatement进行预处理,为了减少代码量,可以将相同的代码封装到一个工具类内。
一、概述:
JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。是Java访问数据库的标准规范
JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。
DBC需要连接驱动,驱动是两个设备要进行通信,满足一定通信数据格式,数据格式由设备提供商规定,设备提供商为设备提供驱动软件,通过软件可以与该设备进行通信。
二、原理:
Java提供访问数据库规范称为JDBC,而生产厂商提供规范的实现类称为驱动。
JDBC是接口,驱动是接口的实现类,没有驱动将无法完成数据库连接,从而不能操作数据库!每个数据库厂商都需要提供自己的驱动,用来连接自己公司的数据库,也就是说驱动一般都由数据库生成厂商提供。
三、开发步骤:
1、导入驱动包
新建java项目,在项目中新建libs文件夹并向其中添加mysql驱动包并右键build path
2、注册驱动.
3、获得连接.
4、获得语句执行平台
5、执行sql语句
6、处理结果
7、释放资源.
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class Demo01 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.注册驱动(包名+类名)
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接对象(导包都导sql里面的,不导jdbc里的;多态!报异常是因为用户输入的串可能写错)后面设置下数据格式
String url="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8";
String user="root";
String password="root";
Connection conn=DriverManager.getConnection(url,user,password);
//System.out.println(conn);报地址为正确sql服务关了可能报错
//3.获取语句执行平台:
Statement sta=conn.createStatement();
//4.执行SQL语句:增-----一套语句执行一句sql语句 返回的是一个Int值,是指执行了几行
String sql="insert into sort(sname) values('小红')";
int row=sta.executeUpdate(sql);
System.out.println(row);
//6.释放资源(先开后关)
sta.close();
conn.close();
}
}
1、导入驱动JAR包:
创建lib目录,用于存放当前项目需要的所有jar包
选择jar包,右键执行build path / Add to Build Path
2、注册驱动:Class.forName(“com.mysql.jdbc.Driver”);
3、获得链接:
jdbc:mysql://localhost:3306/test
JDBC规定url的格式由三部分组成,每个部分中间使用冒号分隔。
第一部分是jdbc,这是固定的;
第二部分是数据库名称;
第三部分是由数据库厂商规定的,我们需要了解每个数据库厂商的要求,mysql的第三部分分别由数据库服务器的IP地址(localhost==127.0.0.1)、端口号(3306),以及数据库名称(test)组成。
4、获得语句执行平台:
常用方法:
① int executeUpdate(String sql); --执行insert 、update、 delete语句.返回执行的行数int值。所有的增删改都执行这个语句
② ResultSet executeQuery(String sql); --执行select语句.返回ResultSet的结果集对象(二维表格)
③ boolean execute(String sql); --执行select返回true 执行其他的语句返回false.(不推荐使用)
5、处理结果集:(执行insert、update、delete无需处理)
ResultSet实际上就是一张二维的表格,我们可以调用其boolean next()方法指向某行记录,当第一次调用next()方法时,便指向第一行记录的位置,这时就可以使用ResultSet提供的getXXX(int col)方法(与索引从0开始不同个,列从1开始)来获取指定列的数据:
rs.next();//指向第一行
rs.getInt(1);//获取第一行第一列的数据
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
public class Demo{
public static void main(String[] args) throws SQLException, ClassNotFoundException {
//1.注册驱动(静态方法)(包名+类名)
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接对象(导包都导sql里面的,不导jdbc里的;多态!报异常是因为用户输入的串可能写错)后面设置下数据格式
String url="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&ServerTimeZone=utf8";
String user="root";
String password="root";
Connection conn=DriverManager.getConnection(url,user,password);
//System.out.println(conn);报地址为正确sql服务关了可能报错
//3.获取语句执行平台:
Statement sta=conn.createStatement();
//4.执行sql语句
String sql="select * from sort";
ResultSet rs=sta.executeQuery(sql);
//5.处理结果集(括号里一般是第1列、第2列,但是可以写字段名)
ArrayList<Sort> arr=new ArrayList<Sort>();
while(rs.next()){
//System.out.println(rs.getInt("sid")+"..."+rs.getString("sname"));
Sort sort=new Sort();
sort.setSid(rs.getInt("sid"));
sort.setSname(rs.getString("sname"));
arr.add(sort);
}
System.out.println(arr);
//6.释放资源
rs.close();
sta.close();
conn.close();
}
}
6、释放资源:
使用后的东西都需要关闭!关闭的顺序是先得到的后关闭,后得到的先关闭。
五、预处理对象:
使用PreparedStatement预处理对象时,建议每条sql语句所有的实际参数,都使用逗号分隔。
String sql = “insert into sort(sid,sname) values(?,?)”;
PreparedStatement预处理对象代码:
PreparedStatement psmt = conn.prepareStatement(sql)
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.Scanner;
public class Demo02 {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
//1.注册驱动(静态方法)(包名+类名)
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接对象(导包都导sql里面的,不导jdbc里的;多态!报异常是因为用户输入的串可能写错)后面设置下数据格式
String url="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8";
String user="root";
String password="root";
Connection conn=DriverManager.getConnection(url,user,password);
//System.out.println(conn);报地址为正确sql服务关了可能报错
//3.获取语句执行平台对象:
String sql="select count(*) from user where uname=? and pwd=?";
PreparedStatement pst=conn.prepareStatement(sql);
//4.执行sql语句
Scanner sc=new Scanner(System.in);
System.out.println("请出入用户名:");
String uname=sc.next();
System.out.println("请输入密码:");
String pwd=sc.next();
//给sql语句的?赋值
pst.setString(1,uname);
pst.setString(2, pwd);
ResultSet rs= pst.executeQuery();//()里不能写sql
//5.处理结果集
int count=0;
while(rs.next()){
count=rs.getInt(1);//因为就一列
System.out.println(count);
}
//6.释放资源
rs.close();
pst.close();
conn.close();
}
}
六、JDBC工具类:
“获得数据库连接”操作,将在以后的增删改查所有功能中都存在,可以封装工具类JDBCUtils。提供获取连接对象的方法,从而达到代码的重复利用。
package com.oracle.demo01;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
封装工具类
*/
public class JDBCUtils {
//获取连接对象的方法(静态的)
public static Connection getConnnections(){
Connection conn=null;
try {
//1.注册驱动(静态方法)(包名+类名)
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接对象(导包都导sql里面的,不导jdbc里的;多态!报异常是因为用户输入的串可能写错)后面设置下数据格式
String url="jdbc:mysql://localhost:3306/java0603?useUnicode=true&characterEncoding=UTF-8";
String user="root";
String password="123456";
conn=DriverManager.getConnection(url,user,password);
} catch (ClassNotFoundException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
//释放资源
public static void close(Connection conn,Statement sta){
if(sta!=null){
try {
sta.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//释放资源2
public static void close(Connection conn,Statement sta,ResultSet rs){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(sta!=null){
try {
sta.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
使用工具类
*/
public class Demo05 {
public static void main(String[] args) throws SQLException {
add();
}
//新增分类Sort
public static void add() throws SQLException{
//1.获得连接对象
Connection conn=JDBCUtils.getConnnections();
//测试下是地址不System.out.println(conn);
//2.获取语句执行平台
String sql="insert into sort (sname) values(?)";
PreparedStatement pst=conn.prepareStatement(sql);
//3.执行sql
pst.setString(1, "打火机");
int row=pst.executeUpdate();
System.out.println(row);
//4.释放资源
JDBCUtils.close(conn, pst);
}
}
七、PreparedStatement和Statement的区别 ?
SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
使用PreparedStatement(预编译对象)可以用来解决sql注入问题,在执行多次插入数据时,Statement需要编译多次执行多次,而PreparedStatement则需要编译一次执行多次
八、Api接口
DriverManager驱动管理类
registDriver(Driver对象):注册驱动,不推荐使用
getConnection(url,user,pwd):获取连接
Connection 连接对象接口
createStatement():生成命令对象
prepareStatement(sql):生成预编译命令对象
Statement命令对象接口
executeUpdate(sql):执行增删改语句,返回受影响的行数
executeQuery(sql):执行查询语句,返回结果集
execute(sql):执行任意sql语句,返回boolean
PreparedStatement预编译命令对象接口
executeUpdate():执行增删改语句,返回受影响的行数
executeQuery():执行查询语句,返回结果集
execute():执行任意sql语句,返回boolean
setXX(占位符索引,占位符的值):设置对应索引的占位符的值,类型为XX类型
setObject(占位符索引,占位符的值):设置对应索引的占位符的值,类型为Object类型
ResultSet结果集对象接口
next():下移一行,返回当前行是否有值
previous():上移一行,返回当前行是否有值
getXX(列索引|列名|别名):返回对应列的值,接收类型为XX
getObject(列索引|列名|别名):返回对应列的值,接收类型为Object
九、批处理
当需要成批插入或者更新记录时。可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率。
JDBC的批量处理语句包括下面两个方法:
addBatch():添加需要批量处理的SQL语句或参数
executeBatch():执行批量处理语句;
clearBatch():清空批处理包的语句
通常我们会遇到两种批量执行SQL语句的情况:
①多条SQL语句的批量处理
②一个SQL语句的批量传参
注意:JDBC连接MySQL时,如果要使用批处理功能,请再url中加参数?rewriteBatchedStatements=true
例子:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import org.junit.Test;
public class TestBatch {
/**
没有使用批处理
*/
@Test
public void noBatch()throws Exception{
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/test";
String user = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url, user, password);
String sql = "INSERT INTO t_department(dname,description) VALUES(?,?)";
PreparedStatement st = conn.prepareStatement(sql);
for(int i=0; i<1000; i++){
st.setString(1, "测试部门" + i);
st.setString(2, "测试部门描述" + i);
st.executeUpdate();
}
st.close();
conn.close();
}
/**
使用批处理
*/
@Test
public void useBatch()throws Exception{
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true";
String user = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url, user, password);
String sql = "INSERT INTO t_department(dname,description) VALUES(?,?)";
PreparedStatement st = conn.prepareStatement(sql);
for(int i=0; i<1000; i++){
st.setString(1, "测试部门" + i);
st.setString(2, "测试部门描述" + i);
st.addBatch();
}
st.executeBatch();
st.close();
conn.close();
}
}
十、事务
JDBC程序中当一个连接对象被创建时,默认情况下是自动提交事务:每次执行一个 SQL 语句时,如果执行成功,就会向数据库自动提交,而不能回滚。
JDBC程序中为了让多个 SQL 语句作为一个事务执行:(重点)
调用 Connection 对象的 setAutoCommit(false); 以取消自动提交事务
在所有的 SQL 语句都成功执行后,调用 commit(); 方法提交事务
在其中某个操作失败或出现异常时,调用 rollback(); 方法回滚事务
若此时 Connection 没有被关闭, 则需要恢复其自动提交状态 setAutoCommit(true);
例子
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TestTransaction {
public static void main(String[] args){
Connection conn = null;
try {
//1、连接数据库
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/test";
String user = "root";
String password = "root";
conn = DriverManager.getConnection(url, user, password);
//设置手动提交
conn.setAutoCommit(false);
String sql1 = "update t_department set description = ? where did = ?";
PreparedStatement pst1 = conn.prepareStatement(sql1);
pst1.setObject(1, "挣大钱的");
pst1.setObject(2, 4);
int len1 = pst1.executeUpdate();
System.out.println(len1>0?"更新部门信息成功":"更新部门信息失败");
pst1.close();
String sql2 = "update t_employee set salary = salary + ? where did = ?";
PreparedStatement pst2 = conn.prepareStatement(sql2);
pst2.setObject(1, 20000);
pst2.setObject(2, 4);
int len2 = pst2.executeUpdate();
System.out.println(len2>0?"更新部门信息成功":"更新部门信息失败");
pst2.close();
conn.commit();
}catch (Exception e) {
try {
if(conn!=null){
conn.rollback();
}
} catch (SQLException e1) {
e1.printStackTrace();
}
} finally{
try {
if(conn!=null){
//恢复自动提交
conn.setAutoCommit(true);
//释放连接
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}