JDBC介绍
JDBC(Java DataBase Connectivity)是Java和数据库之间的一个桥梁,是一个规范而不是一个实现,能够执行SQL语句。它由一组用Java语言编写的类和接口组成。各种不同类型的数据库都有相应的实现。
JDBC API
JDBC API:java.sql.*
里面规定了与各种数据库服务器操作的标准接口。
(另外需要一个相应数据库的驱动jar包)
JDBC编程步骤
1.装载相应数据库的JDBC驱动并进行初始化
访问MySQL数据库需要用到第三方的类,这些第三方的类,都被压缩在一个.Jar的文件里。
2.建立JDBC和数据库之间的Connection连接
数据库服务端的IP地址:127.0.0.1 (这是本机,如果连接其他电脑上的数据库,需填写相应的IP地址)
数据库的端口号: 3306 (mysql专用端口号)
数据库名称 exam(根据你自己数据库中的名称填写)
编码方式 UTF-8
账号 root
密码 admin(如果你在创建数据库的时候没有使用默认的账号和密码,请填写自己设置的账号和密码)
public static void testConnect() throws Exception
{
// 注册MySQL驱动 (可以省略这一步)
Class.forName("com.mysql.jdbc.Driver");
// 连接MySQL服务器
String username= "root"; //用户名
String password = "a1b2c3"; //密码
// IP地址 // 连接的数据库名称
String connectionUrl = "jdbc:mysql://127.0.0.1:3306/af_school?useUnicode=true&characterEncoding=UTF-8";
Connection conn = DriverManager.getConnection(connectionUrl, username, password);
System.out.println("连接成功!");
conn.close();
System.out.println("关闭连接!");
}
注:不同的数据库服务器 ( Oracle, MySQL , SQLServer) 的 Connection URL的格式是不同的
其中,
jdbc:mysql:// 表明连接的是MySQL服务器
127.0.0.1:3306 是服务器的IP和端口
af_school 是数据库名字
useUnicode和characterEncoding参数用于指定交互传输用的字符编码
Connection是与特定数据库连接回话的接口,使用的时候需要导包,而且必须在程序结束的时候将其关闭。getConnection方法也需要捕获SQLException异常。
因为在进行数据库的增删改查的时候都需要与数据库建立连接,所以可以在项目中将建立连接写成一个工具方法,用的时候直接调用即可
语法分析
1.java.sql.*下规定了标准接口,而MySQL驱动里则是各个接口的实现。
2.MySQL驱动的内部封装了与服务器的交互协议。
3.Class.forName(“com.mysql.jdbc.Driver”);
这一行用户显示注册MySQL驱动,可以省略。
补充说明:
为什么 Class.forName(“com.mysql.jdbc.Driver”) 这一句可以省略?
解答:在早期的JAVA里,是需要加一行的, 在com.mysql.jdbc.Driver这个类有一个静态代码块,类似如下的代码
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
}
catch (SQLException E)
{
throw new RuntimeException("Can't register driver!");
}
}
所以,当Class.forName()执行时会执行这几行static代码,从而把这个Driver注册给DriverManager。
不过,大概从JDK1.6之后,就另出一个ServiceProvider机制,自动地从 META-INF/service/目录下提取了。如下图,在mysql-connector-jar-5.1.7-bin.jar里,可以看到有这个文件,所以会被ServiceProvider框架自动发现、并自动注册到DriverManager里。
3.创建Statement或者PreparedStatement接口,执行SQL语句
JDBC查询数据
public static void testQuery() throws Exception
{
// 注册MySQL驱动 (可以省略这一步)
Class.forName("com.mysql.jdbc.Driver");
// 连接MySQL服务器
String username= "root"; //用户名
String password = "a1b2c3"; //密码
// IP地址 // 连接的数据库名称
String connectionUrl = "jdbc:mysql://127.0.0.1:3306/af_school?useUnicode=true&characterEncoding=UTF-8";
Connection conn = DriverManager.getConnection(connectionUrl, username, password);
System.out.println("连接成功!");
///
// 数据库查询, Statement语句 ResultSet结果集
Statement stmt = conn.createStatement();
//可以先再SQLyog中检查一下SQL语句对不对
ResultSet rs = stmt.executeQuery("SELECT * FROM student");
//如果有数据,rs.next()返回true
while(rs.next())
{
// 取出这一行记录
int id = rs.getInt("id");
String name = rs.getString("name");
String phone = rs.getString("phone"); // 可能为null
Date birthday = rs.getDate("birthday");
System.out.println(id + "\t" + name + "\t" + phone );
}
//
conn.close();
System.out.println("关闭连接!");
}
JDBC插入数据
public static void testInsert() throws Exception
{
// 注册MySQL驱动 ( 注:统一加上这一步吧 ! )
// 将来有些运行环境 下不支持驱动的自动加载,例如,Java Web的环境 里, 所以统一加上这句
Class.forName("com.mysql.jdbc.Driver");
// 连接MySQL服务器
String username= "root";
String password = "a1b2c3";
String connectionUrl = "jdbc:mysql://127.0.0.1:3306/af_school?useUnicode=true&characterEncoding=UTF-8";
Connection conn = DriverManager.getConnection(connectionUrl, username, password);
System.out.println("连接成功!");
///
//构建SQL语句,可再SQLyog写好,再拿到代码中来
String sql = "INSERT INTO student(`id`,`name`,`birthday`) "
+ "VALUES ('20181200', '韩', '1997-4-19') ";
System.out.println("SQL: "+ sql);
Statement stmt = conn.createStatement();
stmt.execute(sql);
int count = stmt.getUpdateCount(); //查询受影响的行数
System.out.println("受影响的行数为: " + count);
//
conn.close();
System.out.println("关闭连接!");
}
// 有自增主键时,可以取回新增的主键的值
public static void testInsert2() throws Exception
{
// 连接MySQL服务器
String username= "root";
String password = "a1b2c3";
String connectionUrl = "jdbc:mysql://127.0.0.1:3306/af_school?useUnicode=true&characterEncoding=UTF-8";
Connection conn = DriverManager.getConnection(connectionUrl, username, password);
System.out.println("连接成功!");
///
String sql = "INSERT INTO leave_event(`stuId`,`daysFrom`,`daysTo`,`type`,`reason`) "
+ "VALUES ('20180004', '2018-03-24', '2018-03-30', '2', '出国') ";
System.out.println("SQL: "+ sql);
Statement stmt = conn.createStatement();
stmt.execute(sql, Statement.RETURN_GENERATED_KEYS);
// 取得自动生成的主键的值
ResultSet rs = stmt.getGeneratedKeys();
while(rs.next())
{
int id = rs.getInt(1);
System.out.println("产生的主键是:"+id);
}
//
conn.close();
System.out.println("关闭连接!");
}
当主键设置为自增的时候:
1.插入数据时,不写该字段
2.执行时指定Statement.RETURN_GENERATED_KEYS
3.取出返回的自增主键
JDBC删除和执行
public static void testDelete() throws Exception
{
// 注册MySQL驱动 ( 注:统一加上这一步吧 ! )
// 将来有些运行环境 下不支持驱动的自动加载,例如,Java Web的环境 里, 所以统一加上这句
Class.forName("com.mysql.jdbc.Driver");
// 连接MySQL服务器
String username= "root";
String password = "a1b2c3";
String connectionUrl = "jdbc:mysql://127.0.0.1:3306/af_school?useUnicode=true&characterEncoding=UTF-8";
Connection conn = DriverManager.getConnection(connectionUrl, username, password);
System.out.println("连接成功!");
///
//构建SQL语句,可再SQLyog写好,再拿到代码中来
String sql = "DELETE FROM `af_school`.`student` WHERE `id` = '20181200' ";
System.out.println("SQL: "+ sql);
Statement stmt = conn.createStatement();
stmt.execute(sql);
int count = stmt.getUpdateCount(); //查询受影响的行数
System.out.println("受影响的行数为: " + count);
//
conn.close();
System.out.println("关闭连接!");
}
public static void testUpData() throws Exception
{
// 注册MySQL驱动 ( 注:统一加上这一步吧 ! )
// 将来有些运行环境 下不支持驱动的自动加载,例如,Java Web的环境 里, 所以统一加上这句
Class.forName("com.mysql.jdbc.Driver");
// 连接MySQL服务器
String username= "root";
String password = "a1b2c3";
String connectionUrl = "jdbc:mysql://127.0.0.1:3306/af_school?useUnicode=true&characterEncoding=UTF-8";
Connection conn = DriverManager.getConnection(connectionUrl, username, password);
System.out.println("连接成功!");
///
//构建SQL语句,可再SQLyog写好,再拿到代码中来
String sql = "UPDATE `af_school`.`student` SET `sex` = '0' , `phone` = '123456789123' WHERE `id` = '20181200' ";
System.out.println("SQL: "+ sql);
Statement stmt = conn.createStatement();
stmt.execute(sql);
int count = stmt.getUpdateCount(); //查询受影响的行数
System.out.println("受影响的行数为: " + count);
//
conn.close();
System.out.println("关闭连接!");
}
SQL语句可以先再SQLyog中尝试,再写到JDBC中。
PreparedStatement预处理查询
public static void testQuery() throws Exception
{
// 注册MySQL驱动 ( 注:统一加上这一步吧 ! )
// 将来有些运行环境 下不支持驱动的自动加载,例如,Java Web的环境 里, 所以统一加上这句
Class.forName("com.mysql.jdbc.Driver");
// 连接MySQL服务器
String username= "root";
String password = "a1b2c3";
String connectionUrl = "jdbc:mysql://127.0.0.1:3306/af_school?useUnicode=true&characterEncoding=UTF-8";
Connection conn = DriverManager.getConnection(connectionUrl, username, password);
System.out.println("连接成功!");
///
// 1 构造一个SQL, 参数值用?号代替,称为占位符
String sql = "INSERT INTO student (id,name,birthday) VALUES (?, ?, ?) ";
// 2 创建 PreparedStatement 对象 ( 与MySQL产生一次交互 )
PreparedStatement ptmt = conn.prepareStatement(sql);
// 3 设置参数值
ptmt.setInt(1, 20183001);
ptmt.setString(2, "小新");
ptmt.setString(3, "1993-3-10");
// 4 执行查询
ptmt.execute();
//
conn.close();
System.out.println("关闭连接!");
}
普通查询处理步骤:
MySQL接收SQL请求
解析SQL请求
执行查询
返回结果
预处理查询处理步骤:
MySQL接收预处理的SQL
解析SQL请求
服务器收到参数的值
执行查询
返回结果
显然,再连续执行多个结构相同、参数不同的查询时,使用预处理技术有性能优势。
预处理:先传结构,再传参数
处理多个结构相同的查询时才有优势
并不是所有服务器都支持预处理(MySQL支持)
预处理查询结构
// 1 构造一个SQL, 参数值用?号代替,称为占位符
String sql = "INSERT INTO student (id,name,birthday) VALUES (?, ?, ?) ";
// 2 创建 PreparedStatement 对象 ( 与MySQL产生一次交互 )
PreparedStatement ptmt = conn.prepareStatement(sql);
// 3 设置参数值
ptmt.setInt(1, 20183001);
ptmt.setString(2, "小新");
ptmt.setString(3, "1993-3-10");
// 4 执行查询
ptmt.execute();
注意: ? 左右不要加上单引号
以下为错误写法:
String sql = "INSERT INTO student (id,name,birthday) VALUES (’?’, ‘?’, ‘?’) ";
它这里就是特殊的写法,一个问号表示一个预留的位置。