JDBC(Java DataBase Connectivity)就是Java数据库连接。即使用Java语言操作数据库
由SUN公司提供的一套访问数据库的规范,并提供连接数据库的协议标准。各个数据库厂商遵循SUN的规范提供一套访问自己公司数据库服务器的API。
操作步骤:
/**
* 加载驱动类,在加载驱动类前需要导入mysql的jar包。
* 这个步骤目的是为了调用DriverManager.registerDriver(driver);方法。
* 为什么可以Class.forName就可以实现?是因为com.mysql.jdbc.Driver里面有静态代码块实现了注册自己到DriverManager方法。静态代码块会在加载类时执行。
*
* JDBC4.0之后,每个驱动jar包的META-INF/services目录下提供了一个名为java.sql.Driver的文件。
* 文件的内容就是该接口的实现类。所以加载驱动类步骤可以省略。低版本则不可以
*/
Class.forName("com.mysql.jdbc.Driver");
// 使用url username password 得到数据库连接
Connection conn = DriverManager.getConnection(url, username, password);
public class Demo {
public void fun() {
/**
* 第一步:获取连接
* 通过DriverManager获取数据库连接
*/
// JDBC四大参数
String driverClassName = "com.mysql.jdbc.Driver";
// JDBC协议格式:jdbc:厂商名称:子协议(由厂商自定义)
// MySQL子协议结构://主机:端口号/数据库名称
String url = "jdbc:mysql://localhost:3306/mydb";
String username = "root";
String password = "123456";
Connection conn = null;
Statement stm = null;
ResultSet rs = null;
try {
// 加载驱动类
Class.forName(driverClassName);
// 使用url username password 得到数据库连接
conn = DriverManager.getConnection(url, username, password);
/**
* 第二步:对数据库进行增、删、改
* 1、通过Connection对象创建Statement
* 2、调用int executeUpdate(String sql); 发送DML、DDL
*/
stm = conn.createStatement();
// 增
String sql = "INSERT INTO student VALUES('student_10', 'XiaoMing', 10, 'male')";
int ret = stm.executeUpdate(sql);
System.out.println(ret);
// 改
sql = "UPDATE student SET age=100, gender='male' WHERE name='XiaoMing'";
ret = stm.executeUpdate(sql);
System.out.println(ret);
// 删
sql = "DELETE FROM student";
ret = stm.executeUpdate(sql);
System.out.println(ret);
/**
* 第三步:对数据库进行查操作
* 1、调用ResultSet rs = executeQuery(String querySql);
* 2、解析查询结果
*/
// 查
sql = "SELECT * FROM student";
rs = stm.executeQuery(sql);
System.out.println(rs);
/**
* 解析查询结果
* ResultSet内容有一个行光标
* 提供的next()方法可以将光标向下移动1行
* 提供的get方法可以获取数据,比如:
* getInt(1),getInt("name"),getString(1),getDouble(1) ...
* 1、把行光标移动到数据位置 boolean next(); 如果返回false则数据不存在。
*/
while(rs.next()) {
String number = rs.getString(1);
String name = rs.getString("name");
int age = rs.getInt("age");
String gender = rs.getString("gender");
System.out.println("number:" + number + " ,name:" + name + " ,age:"+age+" ,gender:" + gender);
}
} catch(SQLException e) {
e.printStackTrace();
} catch(ClassNotFoundException e) {
e.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
} finally {
/**
* 四、关闭资源
*/
if (rs != null) {
rs.close();
}
if (stm != null) {
stm.close();
}
if (conn != null) {
conn.close();
}
}
}
}
ResultSet表示结果集,其内部维护一个行光标(游标)且提供了系列方法来移动光标。
结果集特性(当使用createStatement生成Statement时,结果集的特性就确定了):
Connection 的 createStatement 方法有两个实现,区分结果集是否可滚动:
结果集光标移动的前提是结果集是可滚动的。如果结果集不可滚动,则只可以使用next()移动光标。
PreparedStatement是Statement的子接口。
他的优势在于:
public class Demo {
/**
* 演示SQL攻击,
* 正常输入 name + gender 可以正确输出查询到的学生信息。
* 但是如果输入的 name与gender 都是 "x' or 'a'='a" 则条件永远为真,查询到的是所有学生数据。
* 因为如果照这样输入则sql变成了:
* SELECT * FROM student WHERE name='x' or 'a'='a' and gender='x' or 'a'='a'
*/
public void fun(String name, String gender) {
// JDBC四大参数
String driverClassName = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/mydb";
String username = "root";
String password = "123456";
Connection conn = null;
Statement stm = null;
ResultSet rs = null;
try {
// 加载驱动类
Class.forName(driverClassName);
// 使用url username password 得到数据库连接
conn = DriverManager.getConnection(url, username, password);
stm = conn.createStatement();
// SQL模板,所有参数用?代替
String sql = "SELECT * FROM student WHERE name='" + name + "' and gender='" + gender + "'";
rs = stm.executeQuery(sql);
} catch(SQLException e) {
e.printStackTrace();
} catch(ClassNotFoundException e) {
e.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
} finally {
if (rs != null) {
rs.close();
}
if (stm != null) {
stm.close();
}
if (conn != null) {
conn.close();
}
}
}
public void fun1() {
/**
* 第一步:获取连接
* 通过DriverManager获取数据库连接
*/
// JDBC四大参数
String driverClassName = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/mydb";
String username = "root";
String password = "123456";
Connection conn = null;
PreparedStatement pstm = null;
ResultSet rs = null;
try {
// 加载驱动类
Class.forName(driverClassName);
// 使用url username password 得到数据库连接
conn = DriverManager.getConnection(url, username, password);
// SQL模板,所有参数用?代替
String sql = "SELECT * FROM student WHERE name=? and gender=?";
pstm = conn.prepareStatement(sql);
// 配置参数
pstm.setString(1, name);
pstm.setString(2, gender);
// 执行查询
rs = pstm.executeQuery();
} catch(SQLException e) {
e.printStackTrace();
} catch(ClassNotFoundException e) {
e.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
} finally {
/**
* 四、关闭资源
*/
if (rs != null) {
rs.close();
}
if (stm != null) {
stm.close();
}
if (conn != null) {
conn.close();
}
}
}
}
SQL执行步骤:
public class JdbcUtil {
private static Properties sProps = null;
// 只需要在类加载时执行一次
static {
// 给sProps初始化,加载dbconfig.properties文件到props对象中
try {
InputStream in = JdbcUtil.class.getClassLoader()
.getResourceAsStream("dbconfig.properties");
sProps = new Properties();
sProps.load(in);
} catch(IOException e) {
e.printStackTrace();
}
try {
// 加载驱动类
Class.forName(sProps.getProperty("driverClassName"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获取数据库连接
*/
public static Connection getConnection() throws SQLExcetpion {
return DriverManager.getConnection(sProps.getProperty("url"),
sProps.getProperty("username"),
sProps.getProperty("password"));
}
}
数据库类型与Java中类型的对应关系:
领域模型中属性不可以出现java.sql包下的数据。所有需要将java.util包下的数据类型与java.sql包下的数据类型转换。
MySQL的批处理默认是关闭的。需要通过配置:rewriteBatchedStatements=true 打开批处理功能。可以将其添加到url尾部。
public class Demo {
public void fun() throws SQLException {
Connection conn = JdbcUtils.getConnection();
String sql = "INSERT INTO student VALUES(?, ?, ?, ?)";
PreparedStatement pstm = conn.prepareStatement(sql);
// 插入批量数据
for (int i = 0; i < 10000; i ++) {
pstm.setInt(1, i + 1);
pstm.setString(2, "student_" + i);
pstm.setInt(3, i);
pstm.setString(4, i % 2 == 0 ? "male" : "female");
// 将本次参数插入批处理的集合
pstm.addBatch();
}
// 执行批处理,不加rewriteBatchedStatements=true(不使用批处理)时,大概需要6分钟。使用批处理大概需要300ms
pstm.executeBatch();
}
}
createStatement() createStatement(int,int) executeUpdate(String sql) executeQuery(String sql) execute(String sql) getUpdateCount() getResultSet()
TYPE_FORWARD_ONLY TYPE_SCROLL_INSENSITIVE TYPE_SCROLL_SENSITIVE CONCUR_READ_ONLY CONCUR_UPDATABLE
beforeFirst() afterLast() first() last()
isBeforeFirst() isAfterLast() isFirst() isLast() getRow()
previous() next() relative(int row) absolute(int row)
getMetaData() getColumnCount() getColumnName(int colIndex)
prepareStatement(String sql)
addBatch executeBatch rewriteBatchedStatements=true