简介
JDBC:java database connectivity
SUN公司提供的一套操作数据亏的标准规范.
JDBC
与数据库驱动的关系: 接口与实现的关系
JDBC的核心对象
-
DriverManager
:用于注册驱动 -
Connection
: 表示与数据库创建的连接 -
Statement
: 操作数据库sql语句的对象 -
ResultSet
: 结果集或一张虚拟表
JDBC程序
-
导入
mysql-connector-java-xxx-bin.jar
包, 额外注意-
在
配置第三方jar包的路径eclipse
里需要
-
在
配置jar包IDEA
里需要
-
-
实现JDBC的操作
public static void main(String[] args) throws Exception {
// 实现jdbc的操作
// 1. 注册驱动
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
// 2. 创建连接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");
// 3. 得到执行sql语句
Statement statement = conn.createStatement();
// 4. 执行sql语句
String sql = "select * from user;";
ResultSet resultSet = statement.executeQuery(sql);
// 5. 处理结果
while (resultSet.next()) {
// System.out.print(resultSet.getObject(1));
System.out.print(resultSet.getObject(2));
// System.out.print(resultSet.getObject(3));
// System.out.print(resultSet.getObject(4));
}
// 6. 关闭资源
conn.close();
statement.close();
resultSet.close();
}
输出结果
zhangsanlisiwangwu
数据库的结构
数据库内容由此可见, resultSet.getObject(2)
是输出第二列的数据
JDBC常用类和接口详解
1. java.sql.Drivermanager
类: 注册驱动和创建驱动
注册驱动
DriverManager.registerDriver(new com.mysql.jdbc.Driver());不建议使用
原因:
- 导致被注册了两次, 在
com.mysql.jdbc.Driver
内部的静态代码块中也被注册了一次.
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
-
过于依赖数据的驱动
jar
-
解决办法:
使用Class.forName("com.mysql.jdbc.Driver");
来完成加载Driver
- 具体实现
public static void main(String[] args) throws Exception {
// 实现jdbc的操作
// 1. 注册驱动
// DriverManager.registerDriver(Class.forName("com.mysql.jdbc.Driver").newInstance());
Class.forName("com.mysql.jdbc.Driver");
// 2. 创建连接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");
// 3. 得到执行sql语句
Statement statement = conn.createStatement();
// 4. 执行sql语句
String sql = "select * from user;";
ResultSet resultSet = statement.executeQuery(sql);
// 5. 处理结果
while (resultSet.next()) {
// System.out.print(resultSet.getObject(1));
System.out.print(resultSet.getObject(2));
// System.out.print(resultSet.getObject(3));
// System.out.print(resultSet.getObject(4));
}
// 6. 关闭资源
conn.close();
statement.close();
resultSet.close();
}
2. 与数据库建立连接
DriverManager Api- 第一种方式
static Connection getConnection(String url, String user, String password)
// 试图建立到给定数据库 URL 的连接。
getConnection("jdbc:mysql://localhost:3306/test", "root", "root");
- 第二种方式
String url = "jdbc:mysql://localhost:3306/test"
Properties info = new Properties();
info.setProperty("user", "root");
info.setProperty("password","root");
getConnection(String url, Properties info)
// 或者
DriverManager.getConnection("jdbc:mysql://localhost:3306/test?user=root&password=root");
Connection 接口
接口的实现在数据库驱动中, 所有与数据库交互都是基于连接对象的
Statement 接口
操作sql语句, 并返回相应结果的对象
接口的实现在数据库驱动中。用于执行静态 SQL 语句并返回它所生成结果的对象
- 根据查询语句返回结果集。只能执行select语句。
/**
* Executes the given SQL statement, which returns a single
* @param sql an SQL statement to be sent to the database, typically a
* static SQL <code>SELECT</code> statement
* @return a <code>ResultSet</code> object that contains the data produced
* by the given query; never <code>null</code>
*/
ResultSet executeQuery(String sql) throws SQLException;
- 根据执行的DML(insert update delete)语句,返回受影响的行数
/**
* @param sql an SQL Data Manipulation Language (DML) statement, such as <code>INSERT</code>, <code>UPDATE</code> or
* <code>DELETE</code>; or an SQL statement that returns nothing,
* such as a DDL statement.
*
* @return either (1) the row count for SQL Data Manipulation Language (DML) statements
* or (2) 0 for SQL statements that return nothing
*/
int executeUpdate(String sql) throws SQLException;
- 此方法可以执行任意sql语句。返回boolean值,表示是否返回ResultSet结果集。仅当执行select语句,且有返回结果时返回true, 其它语句都返回false;
/**
* @param sql any SQL statement
* @return <code>true</code> if the first result is a <code>ResultSet</code>
* object; <code>false</code> if it is an update count or there are
* no results
* @see #getResultSet
* @see #getUpdateCount
* @see #getMoreResults
*/
boolean execute(String sql) throws SQLException;
ResultSet接口
结果集(客户端存表数据的对象)
-
封装结果集
- 提供一个游标,默认游标指向结果集第一行之前。
- 调用一次next(),游标向下移动一行。
- 提供一些get方法。
-
封装数据的方法
Object getObject(int columnIndex); 根据序号取值,索引从1开始
Object getObject(String ColomnName); 根据列名取值。
/***************************/
System.out.print(resultSet.getObject("id"));
System.out.print(resultSet.getObject("name"));
System.out.print(resultSet.getObject("password"));
java中的数据类型和数据库中的类型的关系
java的数据类型 | 对应的数据库中的类型 |
---|---|
byte |
tityint |
short |
smallint |
int |
int |
long |
bigint |
float |
float |
double |
double |
String |
char varchar |
Date |
date |
常用的接口方法
API | 作用 |
---|---|
boolean next() |
将光标从当前位置向下移动一行 |
int getInt(int colIndex) |
以int 形式获取ResultSet 结果集当前行指定列号值 |
int getInt(String colLabel) |
以int 形式获取ResultSet 结果集当前行指定列名值 |
float getFloat(int colIndex) |
以float 形式获取ResultSet 结果集当前行指定列号值 |
float getFloat(String colLabel) |
以float 形式获取ResultSet 结果集当前行指定列名值 |
String getString(int colIndex) |
以String 形式获取ResultSet 结果集当前行指定列号值 |
String getString(String colLabel) |
以String 形式获取ResultSet 结果集当前行指定列名值 |
Date getDate(int columnIndex); |
以Date 形式获取ResultSet 结果集当前行指定列号值 |
Date getDate(String columnName); |
以Date 形式获取ResultSet 结果集当前行指定列名值 |
void close() |
关闭ResultSet 对象 |
可移动游标的API
API | 作用 |
---|---|
boolean next() |
将光标从当前位置向前移一行。 |
boolean previous() |
将光标移动到此ResultSet 对象的上一行。 |
boolean absolute(int row) |
参数是当前行的索引,从1开始 根据行的索引定位移动的指定索引行。 |
void afterLast() |
将光标移动到末尾,正好位于最后一行之后。 |
void beforeFirst() |
将光标移动到开头,正好位于第一行之前。 |
释放资源的正确方式
public static void main(String[] args) {
Connection conn = null;
Statement statement = null;
ResultSet resultSet = null;
try {
//1、注册驱动
Class.forName("com.mysql.jdbc.Driver");//使用了这个类就加载了
//2、创建连接
conn = DriverManager.getConnection("jdbc:mysql://localhost/test?user=root&password=root");
//3、得到执行sql语句的Statement对象
statement = conn.createStatement();
String sql = "select * from user;";
//4、执行sql语句,并返回结果
resultSet = statement.executeQuery(sql);
//5、处理结果
while(resultSet.next()){
System.out.println(resultSet.getObject(1));
System.out.println(resultSet.getObject(2));
System.out.println(resultSet.getObject(3));
System.out.println(resultSet.getObject(4));
System.out.println(resultSet.getObject(5));
System.out.println("======================");
}
} catch (Exception e) {
// TODO: handle exception
} finally {
//6关闭资源
if(resultSet != null){
try {
resultSet.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
JDBC的CURD操作
CURD 增删改查
C: Create
U: Update
R: Read
D: Delete
封装一个连接数据库工具类
public class DBUtil {
private static String url = "jdbc:mysql://localhost/test";
private static String user = "root";
private static String password = "root";
private static String driverClass = "com.mysql.jdbc.Driver";
static {
try {
Class.forName(driverClass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws Exception {
return DriverManager.getConnection(url, user, password);
}
public static void CloseAll(Connection conn, Statement statement, ResultSet resultSet) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
使用DBUtil实现插入数据
public static void main(String[] args) throws Exception {
// 建立连接
Connection conn = DBUtil.getConnection();
// 创建statement
// preparedStatement:预编译对象, 是Statement对象的子类。
String sql = "INSERT INTO user (id, name, password, email, birthday) " +
"VALUES (?, ?, ?, ?, ?)";
PreparedStatement statement = conn.prepareStatement(sql);
statement.setInt(1, 5);
statement.setString(2, "xiaoniuniu");
statement.setString(3, "124352222");
statement.setString(4, "xiaoniuniu@125.com");
statement.setDate(5, new java.sql.Date(System.currentTimeMillis()));
// 执行插入的sql
int r = statement.executeUpdate();
System.out.println("受影响的行数:" + r);
// 资源关闭
DBUtil.CloseAll(conn, statement, null);
}
更新id=5的用户的密码和邮箱
public static void main(String[] args) throws Exception {
Connection conn = null;
PreparedStatement statement = null;
try {
// 建立连接
conn = DBUtil.getConnection();
// 创建statement
String sql = "UPDATE user SET password=?, email=? WHERE id=?";
statement = conn.prepareStatement(sql);
statement.setString(1, "27823782");
statement.setString(2, "xiaon2iuniu@125.com");
statement.setInt(3, 5);
// 执行插入的sql
int r = statement.executeUpdate();
System.out.println("受影响的行数:" + r);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 资源关闭
DBUtil.CloseAll(conn, statement, null);
}
}
注销id=5的用户
public static void main(String[] args) throws Exception {
Connection conn = null;
PreparedStatement statement = null;
try {
// 建立连接
conn = DBUtil.getConnection();
// 创建statement
String sql = "DELETE FROM user WHERE id=?";
statement = conn.prepareStatement(sql);
statement.setInt(1, 5);
// 执行插入的sql
int r = statement.executeUpdate();
System.out.println("受影响的行数:" + r);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 资源关闭
DBUtil.CloseAll(conn, statement, null);
}
}
查询所有用户数据
class User {
public void User() {
}
private int id;
private String name;
private String password;
private String email;
private Date date;
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setPassword(String password) {
this.password = password;
}
public void setDate(Date date) {
this.date = date;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "name:" + this.name + ", email:" + this.email + ", date:" + this.date + ", password:" + this.password +
", id:" + this.id + ";\n";
}
}
public static void main(String[] args) throws Exception {
Connection conn = null;
PreparedStatement statement = null;
try {
// 建立连接
conn = DBUtil.getConnection();
// 创建statement
String sql = "SELECT * FROM user";
statement = conn.prepareStatement(sql);
// 执行插入的sql
ResultSet r = statement.executeQuery();
ArrayList<User> list = new ArrayList<User>();
while (r.next()) {
User user = new User();
user.setId(r.getInt(1));
user.setName(r.getString(2));
user.setPassword(r.getString(3));
user.setEmail(r.getString(4));
user.setDate(r.getDate(5));
list.add(user);
}
System.out.println("list:" + list);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 资源关闭
DBUtil.CloseAll(conn, statement, null);
}
}
sql注入问题
传统sql
语句的写法不能在代码里写, 即
String sql = "SELECT * FROM user WHERE name= '" + name + "' AND password = '"
+ password + "'";
这样会产生sql
注入的问题
假设name
是lisi
, password
是
ds' or 1='1
那么这个sql将会变成
SELECT * FROM user WHERE name='lisi' AND password='ds' or 1 = '1'
由于
1='1'
是成立的
就会变成
SELECT * FROM user;
为了防止sql注入, 所以要使用PreparedStatement
或者Statement
的形式来写入参数.
JDBC操作事务
当Jdbc
程序向数据库获得一个Connection
对象时,默认情况下这个Connection
对象会自动向数据库提交在它上面发送的SQL语句。若想关闭这种默认提交方式,让多条SQL在一个事务中执行,可使用下列语句:
JDBC控制事务语句
Connection.setAutoCommit(false); // start transaction
Connection.rollback(); // rollback
Connection.commit(); // commit
JDBC操作事务
事务的特性
原子性:指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
一致性:事务必须使数据库从一个一致性状态变换到另外一个一致性状态。转账前和转账后的总金额不变。
隔离性:事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
持久性:指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响
事务的隔离级别
赃读:指一个事务读取了另一个事务未提交的数据。
不可重复读:在一个事务内读取表中的某一行数据,多次读取结果不同。一个事务读取到了另一个事务提交后的数据。(update)
虚读(幻读):是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。 (insert)
数据库通过设置事务的隔离级别防止以上情况的发生:
- 1、READ UNCOMMITTED: 赃读、不可重复读、虚读都有可能发生。
- 2、READ COMMITTED: 避免赃读。不可重复读、虚读都有可能发生。(oracle默认的)
- 4、REPEATABLE READ:避免赃读、不可重复读。虚读有可能发生。(mysql默认)
- 8、SERIALIZABLE: 避免赃读、不可重复读、虚读。
级别越高,性能越低,数据越安全
mysql中:
查看当前的事务隔离级别:SELECT @@TX_ISOLATION;
更改当前的事务隔离级别:SET TRANSACTION ISOLATION LEVEL 四个级别之一。
设置隔离级别必须在事务之前
JDBC设置隔离级别
// 设置隔离级别:必须在开启事务之前。
Connection.setTransactionIsolation(int level);
level
Dbutils
简介
- DBUtils是java编程中的数据库操作实用工具,小巧简单实用。
- DBUtils封装了对JDBC的操作,简化了JDBC操作。可以少写代码。
1.对于数据表的读操作,他可以把结果转成List,Array,Set等java集合,便于程序员操作;
2.对于数据表的写操作,也变得很简单(只需写sql语句)
3.可以使用数据源,使用JNDI,数据库连接池等技术来优化性能--重用已经构建好的数据库连接对象
三大核心类
QueryRunner类
-
QueryRunner
中提供对sql
语句操作的API. - 它主要有三个方法
query() 用于执行select
update() 用于执行insert update delete
batch() 批处理
ResultSetHandler接口
用于定义select操作后,怎样封装结果集.
DbUtils类
一个工具类,定义了关闭资源与事务处理的方法
网友评论