JDBC
JDBC的概念:
客户端操作MYSQL数据库的方式
使用DOS命令行方式使用第三方客户端来访问MySQL:
SQLyog、Navicat、SQLWave、MyDB Studio、EMS SQL Manager for MySQL通过Java来访问MySQL数据库
JDBC的作用
通过JDBC可以让Java操作数据库
JDBC会用到的包
java.sql:JDBC访问数据库的基础包,如:java.sql.Connectionjavax.sql: JDBC访问数据库的扩展包数据库的驱动,各大数据库厂商来实现。如:MySQL的驱动:com.mysql.jdbc.Driver
JDBC四个核心对象
DriverManager:注册驱动
Connection:Java程序和数据库之间的连接(桥梁)
Statement:执行SQL语句的对象(敞篷车,SQL注入问题,弃用)
PreparedStatement:执行SQL语句的对象(安全,推荐)
ResultSet:结果集,保存查询到的数据(用循环逐行调用 rs.next() )
运用Statement方式进行数据库操作
JDBC实现对单表数据增、删、改
准备数据:
CREATE TABLE category
(
cid
INT PRIMARY KEY AUTO_INCREMENT,
cname
VARCHAR(100)
);
INSERT INTO category
(cname
) VALUES('家电');
INSERT INTO category
(cname
) VALUES('服饰');
INSERT INTO category
(cname
) VALUES('化妆品');
API介绍
获取Statement对象
在java.sql.Connection接口中有如下方法获取到Statement对象
Statement
createStatement()
创建一个 Statement 对象来将 SQL 语句发送到数据库
Statement的API介绍
boolean execute(String sql
)
用执行任何SQL语句
,如果是查询返回
true,如果不是查询语句返回
false; 通常不用
int executeUpdate(String sql
)
用于执行增删改等语句
; 返回影响的行数
ResultSet
executeQuery(String sql
)
用于执行查询语句
; 返回查询到的结果集
executeQuery:用于执行查询SQL
executeUpdate:用于执行除查询外的SQL
public class Demo03 {
public static void main(String
[] args
) throws Exception
{
Class
.forName("com.mysql.jdbc.Driver");
Connection conn
= DriverManager
.getConnection("jdbc:mysql://localhost:3306/yyc", "root", "root");
System
.out
.println(conn
);
Statement stmt
= conn
.createStatement();
String sql
= "INSERT INTO category (cname) VALUES ('手机');";
int i
= stmt
.executeUpdate(sql
);
System
.out
.println("影响的行数:" + i
);
sql
= "UPDATE category SET cname='汽车' WHERE cid=4;";
i
= stmt
.executeUpdate(sql
);
System
.out
.println("影响的行数:" + i
);
sql
= "DELETE FROM category WHERE cid=1;";
i
= stmt
.executeUpdate(sql
);
System
.out
.println("影响的行数:" + i
);
stmt
.close();
conn
.close();
}
}
JDBC用Statement实现对单表数据查询
注册驱动获取连接获取到Statement使用Statement执行SQLResultSet处理结果关闭资源
public class Demo04 {
public static void main(String
[] args
) throws Exception
{
Class
.forName("com.mysql.jdbc.Driver");
Connection conn
= DriverManager
.getConnection("jdbc:mysql:///yyc", "root", "root");
Statement stmt
= conn
.createStatement();
String sql
= "SELECT * FROM category;";
ResultSet rs
= stmt
.executeQuery(sql
);
while (rs
.next()) {
int cid
= rs
.getInt("cid");
String cname
= rs
.getString("cname");
System
.out
.println(cid
+ " == " + cname
);
}
rs
.close();
stmt
.close();
conn
.close();
}
}
JDBC事务
事务的作用
让一串SQL完整执行,一处未成功执行全盘回滚;
准备数据
CREATE TABLE account
(
id
INT PRIMARY KEY AUTO_INCREMENT,
NAME
VARCHAR(10),
balance
DOUBLE
);
INSERT INTO account
(NAME
, balance
) VALUES ('张三', 1000), ('李四', 1000);
API介绍
Connection接口中与事务有关的方法
void setAutoCommit(boolean autoCommit
) throws SQLException
;
false:开启事务, ture:关闭事务
void commit() throws SQLException
;
提交事务
void rollback() throws SQLException
;
回滚事务
使用步骤
注册驱动获取连接
开启事务获取到Statement使用Statement执行SQL
提交或回滚事务关闭资源
public class Demo05 {
public static void main(String
[] args
) {
Connection conn
= null
;
try {
Class
.forName("com.mysql.jdbc.Driver");
conn
= DriverManager
.getConnection("jdbc:mysql:///yyc", "root", "root");
conn
.setAutoCommit(false);
Statement pstmt
= conn
.createStatement();
String sql
= "UPDATE account SET balance = balance - 500 WHERE id=1;";
pstmt
.executeUpdate(sql
);
sql
= "UPDATE account SET balance = balance + 500 WHERE id=2;";
pstmt
.executeUpdate(sql
);
pstmt
.close();
System
.out
.println("成功,提交事务");
conn
.commit();
} catch (Exception e
) {
try {
System
.out
.println("出了异常,回滚事务");
conn
.rollback();
} catch (SQLException e1
) {
e1
.printStackTrace();
}
} finally {
try {
conn
.close();
} catch (SQLException e
) {
e
.printStackTrace();
}
}
}
}
编写JDBC工具类
编写JDBC工具类步骤
将固定字符串定义为常量
在静态代码块中注册驱动
提供一个获取连接的方法static Connection getConneciton();
定义关闭资源的方法close(Connection conn, Statement stmt, ResultSet rs)
重载关闭方法close(Connection conn, Statement stmt)
`JDBCUtils
.java`
public class JDBCUtils {
private static final String DRIVER_CLASS
= "com.mysql.jdbc.Driver";
private static final String URL
= "jdbc:mysql:///yyc";
private static final String USER
= "root";
private static final String PASSWORD
= "root";
static {
try {
Class
.forName(DRIVER_CLASS
);
} catch (ClassNotFoundException e
) {}
}
public static Connection
getConnection() throws SQLException
{
InputStream is
= JDBCUtils
.class.getResourceAsStream("/jdbc.properties");
Properties pp
= new Properties();
pp
.load(is
);
Connection conn
= DriverManager
.getConnection(URL
, pp
);
return conn
;
}
public static void close(Connection conn
, Statement stmt
) {
close(conn
, stmt
, null
);
}
public static void close(Connection conn
, Statement stmt
, ResultSet rs
) {
if (rs
!= null
) {
try {
rs
.close();
} catch (SQLException e
) {}
}
if (stmt
!= null
) {
try {
stmt
.close();
} catch (SQLException e
) {}
}
if (conn
!= null
) {
try {
conn
.close();
} catch (SQLException e
) {}
}
}
}
SQL注入问题
请输入用户名:
hehe
请输入密码:
a
' or '1'='1
"SELECT * FROM user WHERE name='" + name
+ "' AND password='" + password
+ "';";
"SELECT * FROM user WHERE name='hehe' AND password='a' or '1'='1';"
让用户输入的密码和SQL语句进行字符串拼接。用户输入的内容作为了SQL语句语法的一部分,改变了原有SQL真正的意义,导致数据库访问出现安全问题
运用PreparedStatement方式进行数据库操作
PreparedStatement的API介绍
在java.sql.PreparedStatement中有设置SQL语句参数,和执行参数化的SQL语句的方法
void setDouble(int parameterIndex
, double x
) 将指定参数设置为给定 Java
double 值。
void setFloat(int parameterIndex
, float x
) 将指定参数设置为给定 Java REAL 值。
void setInt(int parameterIndex
, int x
) 将指定参数设置为给定 Java
int 值。
void setLong(int parameterIndex
, long x
) 将指定参数设置为给定 Java
long 值。
void setObject(int parameterIndex
, Object x
) 使用给定对象设置指定参数的值。
void setString(int parameterIndex
, String x
) 将指定参数设置为给定 Java String 值。
ResultSet
executeQuery()
在此 PreparedStatement 对象中执行 SQL 查询,并返回该查询生成的ResultSet对象。
int executeUpdate()
在此 PreparedStatement 对象中执行 SQL 语句,该语句必须是一个 SQL 数据操作语言DML语句,比如 INSERT、UPDATE 或 DELETE 语句;或者是无返回内容的 SQL 语句,比如 DDL 语句。
PreparedSatement使用步骤
获取连接编写SQL语句,未知内容使用?占位:"SELECT * FROM user WHERE name=? AND password=?;"; 参数化的SQL获得PreparedStatement对象设置实际参数执行参数化SQL语句关闭资源
PreparedStatement实现增删查改
创建表结构
CREATE TABLE employee
(
id
INT PRIMARY KEY AUTO_INCREMENT,
NAME
VARCHAR(20),
age
INT,
address
VARCHAR(50)
);
添加数据
向Employee表添加3条记录
public static void addEmployee() throws Exception
{
Connection conn
= JDBCUtils
.getConnection();
String sql
= "INSERT INTO employee VALUES (NULL, ?, ?, ?);";
PreparedStatement pstmt
= conn
.prepareStatement(sql
);
pstmt
.setString(1, "刘德华");
pstmt
.setInt(2, 57);
pstmt
.setString(3, "香港");
int i
= pstmt
.executeUpdate();
System
.out
.println("影响的行数:" + i
);
pstmt
.setString(1, "张学友");
pstmt
.setInt(2, 55);
pstmt
.setString(3, "澳门");
i
= pstmt
.executeUpdate();
System
.out
.println("影响的行数:" + i
);
pstmt
.setString(1, "黎明");
pstmt
.setInt(2, 52);
pstmt
.setString(3, "香港");
i
= pstmt
.executeUpdate();
System
.out
.println("影响的行数:" + i
);
JDBCUtils
.close(conn
, pstmt
);
}
PreparedStatement删除数据
删除id为2的员工
public static void deleteEmployee() throws Exception
{
Connection conn
= JDBCUtils
.getConnection();
String sql
= "DELETE FROM employee WHERE id=?;";
PreparedStatement pstmt
= conn
.prepareStatement(sql
);
pstmt
.setInt(1, 2);
int i
= pstmt
.executeUpdate();
System
.out
.println("影响的行数:" + i
);
JDBCUtils
.close(conn
, pstmt
);
}
PreparedSatement查询数据
实现步骤
定义Employee类得到连接对象得到PreparedStatement对象编写SQL语句并执行,保存ResultSet创建一个集合用于保存所有的员工对象每次循环将一条记录存放到一个员工对象中把员工对象放到集合中关闭资源遍历集合,循环输出员工对象
代码
public class Employee {
private int id
;
private String name
;
private int age
;
private String address
;
public Employee() {
}
public Employee(int id
, String name
, int age
, String address
) {
this.id
= id
;
this.name
= name
;
this.age
= age
;
this.address
= address
;
}
public int getId() {
return id
;
}
public void setId(int id
) {
this.id
= id
;
}
public String
getName() {
return name
;
}
public void setName(String name
) {
this.name
= name
;
}
public int getAge() {
return age
;
}
public void setAge(int age
) {
this.age
= age
;
}
public String
getAddress() {
return address
;
}
public void setAddress(String address
) {
this.address
= address
;
}
@Override
public String
toString() {
return "Employee2 [id=" + id
+ ", name=" + name
+ ", age=" + age
+ ", address=" + address
+ "]";
}
}
public static void queryEmployee() throws Exception
{
Connection conn
= JDBCUtils
.getConnection();
String sql
= "SELECT * FROM employee WHERE id<?;";
PreparedStatement pstmt
= conn
.prepareStatement(sql
);
pstmt
.setInt(1, 26);
ResultSet rs
= pstmt
.executeQuery();
ArrayList
<Employee> list
= new ArrayList<>();
while (rs
.next()) {
int id
= rs
.getInt("id");
String name
= rs
.getString("name");
int age
= rs
.getInt("age");
String address
= rs
.getString("address");
Employee e
= new Employee(id
, name
, age
, address
);
list
.add(e
);
}
for (Employee e
: list
) {
System
.out
.println(e
);
}
JDBCUtils
.close(conn
, pstmt
, rs
);
}
ParameterMetaData元数据
什么是元数据
元数据其实就是定义表的字段
ParameterMetaData作用
ParameterMetaData可用于获取有关PreparedStatement对象中每个参数标记的类型和属性。
select
* from user where name
=? and password
=?
ParameterMetaDataAPI介绍
int getParameterCount() 获取PreparedStatement的SQL语句参数?的个数
int getParameterType(int param
) 获取指定参数的SQL类型。
使用步骤
获取ParameterMetaData对象使用对象调用方法
注意事项
不是所有的数据库驱动都能后去到参数类型(MySQL会出异常)
案例代码
public class Demo01 {
public static void main(String
[] args
) throws Exception
{
Connection conn
= DataSourceUtils
.getConnection();
String sql
= "INSERT INTO student (name, age, score) VALUES (?, ?, ?)";
PreparedStatement stmt
= conn
.prepareStatement(sql
);
ParameterMetaData md
= stmt
.getParameterMetaData();
System
.out
.println("参数个数: " + md
.getParameterCount());
}
}
ResultSetMetaData元数据
ResultSetMetaData作用
ResultSetMetaData可用于获取有关ResultSet对象中列的类型和属性的信息。
如何获取ResultSetMetaData
通过ResultSet的getMetaData()方法来获取到ResultSetMetaData对象
ResultSetMetaDataAPI介绍
int getColumnCount() 返回此 ResultSet对象中的列数
String
getColumnName(int column
) 获取指定列的名称
String
getColumnTypeName(int column
) 获取指定列的数据库特定类型名称
使用步骤
获取ResultSetMetaData对象使用对象调用方法
案例代码
public static void test02() throws SQLException
{
Connection conn
= DataSourceUtils
.getConnection();
String sql
= "SELECT * FROM student WHERE id=1";
PreparedStatement stmt
= conn
.prepareStatement(sql
);
ResultSet rs
= stmt
.executeQuery();
ResultSetMetaData md
= rs
.getMetaData();
int num
= md
.getColumnCount();
System
.out
.println("列数:" + num
);
for (int i
= 0; i
< num
; i
++) {
System
.out
.println("列名:" + md
.getColumnName(i
+ 1));
System
.out
.println("列类型:" + md
.getColumnTypeName(i
+ 1));
System
.out
.println("-----------");
}
}
用方法
案例代码
public static void test02() throws SQLException
{
Connection conn
= DataSourceUtils
.getConnection();
String sql
= "SELECT * FROM student WHERE id=1";
PreparedStatement stmt
= conn
.prepareStatement(sql
);
ResultSet rs
= stmt
.executeQuery();
ResultSetMetaData md
= rs
.getMetaData();
int num
= md
.getColumnCount();
System
.out
.println("列数:" + num
);
for (int i
= 0; i
< num
; i
++) {
System
.out
.println("列名:" + md
.getColumnName(i
+ 1));
System
.out
.println("列类型:" + md
.getColumnTypeName(i
+ 1));
System
.out
.println("-----------");
}
}