目录
1.概念
SUN公司为了简化、统一对数据库的操作,定义了一套Java操作数据库的规范,称之为JDBC。
JDBC全称为:Java Data Base Connectivity(java数据库连接),它主要由接口组成。组成JDBC的2个包:java.sql、javax.sql。开发JDBC应用需要以上2个包的支持外,还需要导入相应JDBC的实现类,即数据库驱动。
Jdbc程序运行完后,切记要释放程序在运行过程中,创建的那些与数据库进行交互的对象,这些对象通常是ResultSet, Statement和Connection对象。特别是Connection对象,它是非常稀有的资源,用完后必须马上释放,如果Connection不能及时、正确的关闭,极易导致系统宕机。Connection的使用原则是尽量晚创建,尽量早的释放。
为确保资源释放代码能运行,资源释放代码也一定要放在finally语句中。
2 JDBC接口的核心API
①Driver接口: 表示java驱动程序接口。所有的具体的数据库厂商来实现此接口。
connect(url, properties): 连接数据库的方法。
其中参数url: jdbc协议:数据库子协议://主机:端口/数据库
常用数据库URL地址的写法:
Oracle写法: jdbc:oracle:thin:@localhost:1521:sid
SqlServer写法jdbc:microsoft:sqlserver://localhost:1433; DatabaseName=sid
MySql写法: jdbc:mysql://localhost:3306/sid
properties一般至少包括:
user: 数据库的用户名
password: 数据库用户密码
②DriverManager类: 驱动管理器类,用于加载驱动,并创建与数据库的链接。DriverManager.registerDriver(driver): 注册驱动类对象
Connection DriverManager.getConnection(url, user, password); 获取连接对象
注:在实际开发中并不推荐采用registerDriver方法注册驱动。原因有二:
一、查看Driver的源代码可以看到,如果采用此种方式,会导致驱动程序注册两次,也就是在内存中会有两个Driver对象。二、程序依赖mysql的api,脱离mysql的jar包,程序将无法编译,将来程序切换底层数据库将会非常麻烦。
推荐方式:Class.forName(“com.mysql.jdbc.Driver”);
采用此种方式不会导致驱动对象在内存中重复出现,并且采用此种方式,程序仅仅只需要一个字符串,不需要依赖具体的驱动,使程序的灵活性更高。
③Connection接口: 表示java程序和数据库的连接对象。客户端与数据库所有交互都是通过connection对象完成的。
Statement createStatement() : 创建Statement对象
PreparedStatement prepareStatement(String sql) 创建PreparedStatement对象
CallableStatement prepareCall(String sql) 创建CallableStatement对象
④Statement接口: 用于执行静态的sql语句
int executeUpdate(String sql) : 执行静态的更新sql语句(DDL,DML)
ResultSet executeQuery(String sql) :执行的静态的查询sql语句(DQL)
⑤PreparedStatement接口:是Statement的子接口。用于执行预编译sql语句
int executeUpdate() : 执行预编译的更新sql语句(DDL,DML)
ResultSet executeQuery() : 执行预编译的查询sql语句(DQL)
Statement VS PreparedStatement:
1.PreperedStatement可以避免SQL注入的问题。
2.Statement会使数据库频繁编译SQL,可能造成数据库缓冲区溢出。PreparedStatement 可对SQL进行预编译,从而提高数据库的执行效率。(oracle、SQL Server支持数据库缓冲区,MySQL并不支持数据库缓冲区)
3.PreperedStatement对于sql中的参数,允许使用占位符的形式进行替换,简化sql语句的编写。
⑥CallableStatement接口:是PreparedStatement的子接口。用于执行存储过程的sql语句(call xxx)
ResultSet executeQuery() : 调用存储过程的方法
⑦ResultSet接口:用于封装查询出来的数据。
Jdbc程序中的ResultSet用于代表SQL语句的执行结果。Resultset封装执行结果时,采用的类似于表格的方式。ResultSet 对象维护了一个指向表格数据行的游标,初始的时候,游标在第一行之前,调用ResultSet.next() 方法,可以使游标指向具体的数据行,进行调用方法获取该行的数据。
ResultSet提供的都是用于获取数据的get方法,可以使用列的索引编号(从1开始)或列的名称(不区分大小写)获取值:
例: getString(int index)
getString(String columnName)
常用的数据类型转换表:
例1:jdbc连接数据库
package day1105;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.util.Properties;
import org.junit.Test;
public class Connect {
private String url="jdbc:mysql://localhost:3306/xiaohua";
private String user="root";
private String password="root";
@Test
//第一种方法
public void test1() throws Exception{
// 1.创建驱动程序类对象
Driver driver=new com.mysql.jdbc.Driver();
Properties props=new Properties();
props.setProperty("user", user);
props.setProperty("password", password);
//2.连接数据库,返回连接对象
Connection conn=driver.connect(url, props);
System.out.println(conn);
}
@Test
//第二种方法,使用驱动管理器类(注册了两次,没必要)
public void test2() throws Exception{
Driver driver=new com.mysql.jdbc.Driver();
//注册驱动程序(可注册多个)
DriverManager.registerDriver(driver);
//连接具体的数据库
Connection conn=DriverManager.getConnection(url, user,password);
System.out.println(conn);
}
@Test
//第二种的改进,使用驱动管理器类(推荐)
public void test3() throws Exception{
//通过得到字节码对象的方式加载静态代码块,从而注册驱动程序
Class.forName("com.mysql.jdbc.Driver");
Connection conn=DriverManager.getConnection(url, user,password);
System.out.println(conn);
}
}
其中:properties:
url=jdbc:mysql//localhost:3306/xiaohua
user=root
password=root
driverClass=com.mysql.jdbc.Driver
例2:Statement对象演示
jdbcUtil.java文件:
package util;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* jdbc工具类
* */
public class jdbcUtil {
private static String url=null;
private static String user=null;
private static String password=null;
private static String driverClass=null;
//静态代码块,只加载一次
static {
try {
//读取properties文件
Properties props=new Properties();
/**
* . 代表java命令运行的目录
* 在java项目下,. java命令的运行目录从项目的根目录开始
* 在web项目下, . java命令的而运行目录从tomcat/bin目录开始
* 所以不能使用点.
*/
//FileInputStream in = new FileInputStream("./src/db.properties");
/**
* 使用类路径的读取方式
* / : 斜杠表示classpath的根目录
* 在java项目下,classpath的根目录从bin目录开始
* 在web项目下,classpath的根目录从WEB-INF/classes目录开始
*/
InputStream in=jdbcUtil.class.getResourceAsStream("/db.properties");
props.load(in);//加载文件
//读取信息
url=props.getProperty("url");
user=props.getProperty("user");
password=props.getProperty("password");
driverClass=props.getProperty("driverClass");
//注册驱动程序
Class.forName(driverClass);
}catch(Exception e) {
e.printStackTrace();
System.out.println("驱动程序注册出错");
}
}
//获取连接对象的方法
public static Connection getConnection() {
try {
Connection conn=DriverManager.getConnection(url,user,password);
return conn;
}catch(SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
//释放资源的方法
public static void close(Connection conn,Statement stmt) {
if(stmt!=null) {
try {
stmt.close();
}catch(SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
if(conn!=null) {
try {conn.close();
}catch(SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
//释放资源的方法
public static void close(Connection conn,Statement stmt,ResultSet rs){
if(rs!=null) {
try {
rs.close();
} catch (SQLException e1) {
e1.printStackTrace();
throw new RuntimeException(e1);
}
}
if(stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
}
statement对象操作DDL、DML、DQL语句:
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import org.junit.Test;
import util.jdbcUtil;
public class StatementDemo {
@Test
public void test1() {
Connection conn=null;
Statement stmt=null;
try {
//1.获取连接对象
conn=jdbcUtil.getConnection();
//2.创建statement对象
stmt=conn.createStatement();
//3.静态SQL语句
//DDL语句
//String sql = "CREATE TABLE student(id INT PRIMARY KEY AUTO_INCREMENT,NAME VARCHAR(20),gender VARCHAR(2))";
//DML语句
String sql = "INSERT INTO student(NAME,gender) VALUES('小华','男')";
//4.发送SQL语句,执行
int count=stmt.executeUpdate(sql);
System.out.println("影响了"+count+"行");
}catch(Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}finally {
//5.关闭连接(先开后关)
jdbcUtil.close(conn, stmt);
}
}
@Test
public void test2() {
Connection conn=null;
Statement stmt=null;
try {
//1.获取连接对象
conn=jdbcUtil.getConnection();
//2.创建statement对象
stmt=conn.createStatement();
//3.静态SQL语句
//DQL语句
String sql="SELECT * FROM student";
//4.发送SQL语句,执行
ResultSet rs=stmt.executeQuery(sql);
//遍历取值
while(rs.next()) {
int id=rs.getInt("id");
String name=rs.getString("name");
String gender=rs.getString("gender");
System.out.println(id+","+name+","+gender);
}
}catch(Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}finally {
//5.关闭连接(先开后关)
jdbcUtil.close(conn, stmt);
}
}
}
DDL的结果:
DML的结果:
DQL的结果:
例3:PreparedStatement对象演示
package day1105;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import org.junit.Test;
import util.jdbcUtil;
public class PreparedStatementDemo {
@Test
public void test1() {
Connection conn=null;
PreparedStatement stmt=null;
try {
//1.获取连接
conn=jdbcUtil.getConnection();
//2.准备预编译的SQL语句
String sql = "INSERT INTO student (NAME,gender) VALUES(?,?)"; //?表示一个参数的占位符
//3.创建PreparedStatement对象,执行预编译语句
stmt=conn.prepareStatement(sql);
//4.设置参数,参数位置从1开始。
stmt.setString(1,"小娜");
stmt.setString(2, "女");
//5.发送参数,执行SQL。
int count=stmt.executeUpdate();
System.out.println("影响了"+count+"行");
}catch(Exception e){
e.printStackTrace();
throw new RuntimeException(e);
}finally {
jdbcUtil.close(conn, stmt);
}
}
@Test
public void test2() {
Connection conn=null;
PreparedStatement stmt=null;
ResultSet rs=null;
try {
//1.获取连接
conn=jdbcUtil.getConnection();
//2.准备预编译的SQL语句
String sql = "SELECT * FROM student";
//3.创建PreparedStatement对象,执行预编译语句
stmt=conn.prepareStatement(sql);
//4.发送参数,执行SQL。
rs=stmt.executeQuery();
while(rs.next()) {
int id=rs.getInt("id");
String name=rs.getString("name");
String gender=rs.getString("gender");
System.out.println(id+","+name+","+gender);
}
}catch(Exception e){
e.printStackTrace();
throw new RuntimeException(e);
}finally {
jdbcUtil.close(conn, stmt,rs);
}
}
}
DML的结果:
DQL的结果:
例4:CallableStatement对象演示
package day1105;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import org.junit.Test;
import util.jdbcUtil;
public class CablleStatementDemo {
@Test
//调用带有输入参数的存储过程
public void test1() {
Connection conn=null;
CallableStatement stmt=null;
ResultSet rs=null;
try {
//获取连接
conn=jdbcUtil.getConnection();
//准备sql
String sql="CALL pro_findById(?)";
//创建CallableStatement对象,并预编译
stmt=conn.prepareCall(sql);
//设置输入参数值
stmt.setInt(1, 1);
//发送参数
rs=stmt.executeQuery();
//遍历结果
while(rs.next()) {
int id=rs.getInt("id");
String name=rs.getString("name");
String gender=rs.getString("gender");
System.out.println(id+","+name+","+gender);
}
}catch(Exception e) {
e.printStackTrace();
throw new RuntimeException();
}finally {
jdbcUtil.close(conn,stmt,rs);
}
}
@Test
//调用带有输入、输出参数的存储过程
public void test2() {
Connection conn=null;
CallableStatement stmt=null;
ResultSet rs=null;
try {
//获取连接
conn=jdbcUtil.getConnection();
//准备sql
//第一个参数是输入参数,第二个参数是输出参数
String sql="CALL pro_findById2(?,?)";
//创建CallableStatement对象,并预编译
stmt=conn.prepareCall(sql);
//设置输入参数值
stmt.setInt(1, 1);
//设置输出参数
stmt.registerOutParameter(2, java.sql.Types.VARCHAR);
//发送参数
stmt.executeQuery();//结果不是返回到结果集ResultSet中,而是输出参数中。
//得到输出参数的值
//索引值:预编译SQL中的输出参数的位置
String result=stmt.getString(2);
System.out.println(result);
}catch(Exception e) {
e.printStackTrace();
throw new RuntimeException();
}finally {
jdbcUtil.close(conn,stmt,rs);
}
}
}
其中,存储过程函数为:
DELIMITER $
CREATE PROCEDURE pro_findById(IN eid INT)
BEGIN
SELECT * FROM student WHERE id=eid;
END $
DELIMITER $
CREATE PROCEDURE pro_findById2(IN eid INT,OUT vname VARCHAR(20))
BEGIN
SELECT NAME INTO vname FROM student WHERE id=eid;
END $
CALL pro_findById(1);
CALL pro_findById2(1,@NAME);
SELECT @NAME
执行结果: