JDBC编程
查询返回的是查询的结果集,修改返回的修改的行数
两个常用API:ODBC和JDBC
ODBC(Open DataBase Connectivity):开放式数据库连接,由Microsoft公司提供
JDBC(Java DataBase Connectivity):Java数据库连接,
JDBC是一种规范,
JDBC访问数据库过程
相关接口和类的作用:
Connection 此接口表示与数据的连接
PreparedStatement 此接口用于执行预编译的 SQL 语句
ResultSet 此接口表示了查询出来的数据库数据结果集
Statement 此接口用于执行 SQL 语句并将数据检索到 ResultSet 中
DriverManager 此类用于加载和卸载各种驱动程序并建立与数据库的连接
ResultSetMetaData 可用于获取关于ResultSet对象中列的类型和属性信息的对象
JDBC数据库访问过程:
- 注册和加载数据库驱动程序
- 通过Connection建立数据连接
- 通过createStatement()方法获取Statement对象
- 构造SQL语句
- 执行SQL语句
- 关闭相关资源
连接数据库的工具类:
package cn.goktech.utils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 连接数据库的工具类
* @author asus
*
*/
public class DBUtil {
//创建连接对象,全部用静态,方便用类名调用
private static Connection conn; //使用static原因:如果不是连接池,一次最好建一个连接,
private Statement state;
private ResultSet rs;//结果集
public static Connection getConnection() throws SQLException{
try {
Class.forName("com.mysql.jdbc.Driver");//Class是反射中常见类,com.mysql.jdbc.Driver是全类名
//通过全类名把该类加载到内存
/*
* url:连接数据库的字符串,-->用于表示协议:连接数据库:/连接数据库/用户:端口/数据库
* user:"root" 数据库的用户
* password:"123456" 数据库的密码
*/
conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/test1806?characterEncoding=utf-8", "root", "123456");
return conn;
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
/*
* 关闭数据库连接
*/
public static void closeConn(Statement state,ResultSet rs,PreparedStatement patmt){
try{
if(rs!=null){
rs.close();
}
if(patmt!=null){
patmt.close();
}
if(state!=null){
state.close();
}
if(conn!=null){
conn.close();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) throws SQLException {
Connection conn = getConnection();
System.out.println(conn);
}
}
创建一个Student类的JavaBean:
package cn.goktech.select;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import cn.goktech.entity.Student;
import cn.goktech.utils.DBUtil;
/**
* 操作数据库的类
* @author asus
*Dao 持久层
*/
public class StudentDao {
private Connection conn;
private Statement state;
private PreparedStatement patmt;
private ResultSet rs;//结果集
/**
* 返回数据库Student中的所有数据
* @return
* @throws SQLException
*/
public List<Student> selectAll() {
List<Student> list = null;
try {
//准备容器(装Student)
list = new ArrayList<>();
//1.获取数据库连接
conn = DBUtil.getConnection();
//2.创建SQL语句
String sql = "select * from student";
//3.创建编译器
state = conn.createStatement();
//4.执行SQL语句
rs = state.executeQuery(sql);
//5.处理结果集
while(rs.next()){//next() 原因:因为是从0开始,0那里是没有数据的,必须next(),即1的地方才有数据
Student stemp = new Student();
stemp.setId(rs.getInt("id"));
stemp.setName(rs.getString(2));
list.add(stemp);
}
return list;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
DBUtil.closeConn(state,rs,patmt);
}
return null;
}
public Student selectById(int id) {
try {
//1.获取数据库连接
conn = DBUtil.getConnection();
//2.创建SQL语句
String sql = "select * from student where id=?";
//3.创建预编译器
patmt = conn.prepareStatement(sql);
patmt.setInt(1, id);
//4.执行SQL语句
rs = patmt.executeQuery();
//5.处理结果集
Student stemp = new Student();
if(rs.next()){//next() 原因:因为是从0开始,0那里是没有数据的,必须next(),即1的地方才有数据
stemp.setId(rs.getInt("id"));
stemp.setName(rs.getString("name"));
stemp.setCity(rs.getString("city"));
stemp.setAge(rs.getInt("age"));
System.out.println("-------------");
// System.out.println(rs.getInt("id"));
// System.out.println(rs.getString("name"));
}
else {
return null;
}
return stemp;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
DBUtil.closeConn(state,rs,patmt);
}
return null;
}
/**
* 通过id更新name
*
* @param id
* @param name
* @return
* 事务:
* 原子性:事务的操作是不可分割的,每一步都属于事务的一部分,某一步出错,全部都不能执行
* 隔离性:多事务存在时,决定事务的存储顺序
* 一致性:多事务在开始后,未结束前数据对外不可见的,保障了事务的并发性
* 持久性:事务对于数据的操作是永久的,就是存在数据库,也就是硬盘中
*/
public boolean updateNameById(int id,String name) {
List<Student> list = null;
try {
//准备容器(装Student)
list = new ArrayList<>();
//1.获取数据库连接
conn = DBUtil.getConnection();
//取消自动提交
conn.setAutoCommit(false);
//2.创建SQL语句
String sql = "update student set name=? where id=?";
//3.创建预编译器
patmt = conn.prepareStatement(sql);
patmt.setString(1, name);
patmt.setInt(2, id);
//4.执行SQL语句
int number = patmt.executeUpdate();
conn.commit();
//5.处理结果集
Student stemp = new Student();
if(number!=0){//next() 原因:因为是从0开始,0那里是没有数据的,必须next(),即1的地方才有数据
return true;
}
else {
return false;
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}finally{
DBUtil.closeConn(state,rs,patmt);
}
return false;
}
public static void main(String[] args) {
StudentDao studentDao = new StudentDao();
List<Student> list = studentDao.selectAll();
list.stream().forEach(System.out::println);//JDK8
// list.stream().forEach(s->System.out.println(s));//入表达式,效果同上
System.out.println("--------------------");
Student s1 = studentDao.selectById(3);
System.out.println(s1);
System.out.println("-------------");
System.out.println(studentDao.updateNameById(1, "xiaohong"));
}
}
代码未执行前,查询数据库中的数据:
select * from student;
执行代码后,控制台输出内容:
在数据库中再执行
select * from student;
如果对数据库进行查询和修改相关操作为以下代码:
package cn.goktech.select;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import cn.goktech.entity.Student;
import cn.goktech.utils.DBUtil;
/**
* 操作数据库的类
* @author asus
*Dao 持久层
*/
public class StudentDao {
private Connection conn;
private Statement state;
private PreparedStatement patmt;
private ResultSet rs;//结果集
/**
* 返回数据库Student中的所有数据
* @return
* @throws SQLException
*/
public List<Student> selectAll() {
List<Student> list = null;
try {
//准备容器(装Student)
list = new ArrayList<>();
//1.获取数据库连接
conn = DBUtil.getConnection();
//2.创建SQL语句
String sql = "select * from student";
//3.创建编译器
state = conn.createStatement();
//4.执行SQL语句
rs = state.executeQuery(sql);
//5.处理结果集
while(rs.next()){//next() 原因:因为是从0开始,0那里是没有数据的,必须next(),即1的地方才有数据
Student stemp = new Student();
stemp.setId(rs.getInt("id"));
stemp.setName(rs.getString(2));// 2 表示第二列,即name字段
stemp.setCity(rs.getString("city"));
stemp.setAge(rs.getInt("age"));
list.add(stemp);
}
return list;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
DBUtil.closeConn(state,rs,patmt);
}
return null;
}
public Student selectById(int id) {
try {
//1.获取数据库连接
conn = DBUtil.getConnection();
//2.创建SQL语句
String sql = "select * from student where id=?";
//3.创建预编译器
patmt = conn.prepareStatement(sql);
patmt.setInt(1, id);
//4.执行SQL语句
rs = patmt.executeQuery();
//5.处理结果集
Student stemp = new Student();
if(rs.next()){//next() 原因:因为是从0开始,0那里是没有数据的,必须next(),即1的地方才有数据
stemp.setId(rs.getInt("id"));
stemp.setName(rs.getString("name"));
stemp.setCity(rs.getString("city"));
stemp.setAge(rs.getInt("age"));
System.out.println("-------------");
// System.out.println(rs.getInt("id"));
// System.out.println(rs.getString("name"));
}
else {
return null;
}
return stemp;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
DBUtil.closeConn(state,rs,patmt);
}
return null;
}
/**
* 通过id更新name
*
* @param id
* @param name
* @return
* 事务:
* 原子性:事务的操作是不可分割的,每一步都属于事务的一部分,某一步出错,全部都不能执行
* 隔离性:多事务存在时,决定事务的存储顺序
* 一致性:多事务在开始后,未结束前数据对外不可见的,保障了事务的并发性
* 持久性:事务对于数据的操作是永久的,就是存在数据库,也就是硬盘中
*/
public boolean updateNameById(int id,String name) {
List<Student> list = null;
try {
//准备容器(装Student)
list = new ArrayList<>();
//1.获取数据库连接
conn = DBUtil.getConnection();
//取消自动提交
conn.setAutoCommit(false);
//2.创建SQL语句
String sql = "update student set name=? where id=?";
//3.创建预编译器
patmt = conn.prepareStatement(sql);
patmt.setString(1, name);
patmt.setInt(2, id);
//4.执行SQL语句
int number = patmt.executeUpdate();
conn.commit();
//5.处理结果集
Student stemp = new Student();
if(number!=0){//next() 原因:因为是从0开始,0那里是没有数据的,必须next(),即1的地方才有数据
return true;
}
else {
return false;
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}finally{
DBUtil.closeConn(state,rs,patmt);
}
return false;
}
public static void main(String[] args) {
StudentDao studentDao = new StudentDao();
List<Student> list = studentDao.selectAll();
list.stream().forEach(System.out::println);//JDK8
// list.stream().forEach(s->System.out.println(s));//入表达式,效果同上
System.out.println("--------------------");
Student s1 = studentDao.selectById(3);
System.out.println(s1);
System.out.println("-------------");
System.out.println(studentDao.updateNameById(1, "xiaohong"));
}
}
PreparedStatement和Statement区别
- PreparedStatement 接口是 Statement 的子接口,它表示一条预编译过的 SQL 语句
- PreparedStatement 对象所代表的 SQL 语句中的参数用问号(?)来表示,调用 PreparedStatement
对象的 setXXX() 方法来设置这些参数. - 使用PreparedStatement可以防范SQL注入
- 使用PreparedStatement效率更高,速度更快