目录
1 JDBC概念
(1)Java提供访问数据库的规范称为JDBC,JDBC是接口。
(2)数据库厂商提供规范的实现类称为驱动,驱动是接口的实现,没有驱动将无法完成数据库连接,从而不能操作数据库。
(3)每个数据库厂商都需要提供自己的驱动,用来连接自己公司的数据库,也就是说驱动一般都由数据库厂商提供。(图中的应用程序可理解为sql语句:即相同的sql语句可用在不同的数据库中)
2 JDBC核心接口、类、基本开发步骤
2.1 JDBC中的核心接口、类
SUN公司提供JDBC开发API、类库(类、接口),可以用于开发任意的关系型数据库,程序员写的代码不会变
JDBC API中的核心类和接口:
(1)接口Driver 数据库驱动程序,Mysql驱动jar包中已经实现了这个类
(2)接口Connection 数据库的连接对象,Mysql驱动jar包中已经实现了这个类
(3)接口Statement 数据库sql语句的执行对象,Mysql驱动jar包中已经实现了这个类
(4)接口ResultSet 数据的查询结果集对象,Mysql驱动jar包中已经实现了这个类
(5)类DriverManager 数据库驱动程序的管理类
2.2 JDBC基本开发步骤(6步)
(1)注册驱动(告诉JVM,使用的数据库驱动程序是谁)
(2)获取接口Connection的实现类对象(数据库连接对象),该对象表明此时已经和数据库建立了连接
(3)使用连接对象获取sql语句执行对象,该对象用于执行sql语句
(4)执行sql语句,获取结果集对象(一般指的是查询语句的结果,非查询语句指的是sql语句执行后所影响的行数)即获取接口ReslutSet实现类对象
(5)处理结果集(一般指的是对查询语句的查询结果进行处理)
(6)释放资源
在如下的代码中,演示了JDBC的基本开发套路,其中的sql语句是一条“插入语句”,数据库的ip端口账号密码是自己的。
public class JdbcDemo {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
//1、注册驱动(告诉虚拟机用哪个数据库的驱动),DriverManager类中的静态方法:registerDriver(参数是Driver接口实现类的对象)
//这样的写法有个问题:创建Driver对象时本身就注册了一个mysql驱动,这样等于“new Driver()”了两次!没必要,怎么办呢?答:把这个Driver类加入到内存方法区中,因为一进内存Driver类中的静态代码块就会运行,而静态代码块中刚好就注册了驱动!
//DriverManager.registerDriver(new Driver());//这个方法不好,应该用反射,把Driver类加载到内存的方法区中
Class.forName("com.mysql.jdbc.Driver");
//2、获取数据库连接对象,调用DriverManager类中的静态方法返回该对象:getConnection(url,账号,密码)
Connection connection = DriverManager.getConnection("jdbc:mysql://IP:port/databasename", "username", "password");
//3、使用连接对象获取sql语句执行对象,使用该对象的createStatement方法
Statement statement = connection.createStatement();
//4、执行sql语句,往person表中写入两行数据,使用sql语句执行对象的execute方法,该方法返回int类型的数据,表示操作成功的行数
String sql = "insert into person values(null,'222','222','默认地址')";
int rows = statement.executeUpdate(sql); //executeUpdate方法执行“增删改”
//5、处理结果集
System.out.println(rows);
//6、释放资源
statement.close();
connection.close();
}
}
3 JDBC实现对查询结果集的处理
在如下的代码中,通过JDBC实现了数据的查询,涉及到了对结果集的基本处理:
(1)遍历每一条查询结果、打印每一条查询结果
public class JdbcDemo02 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1、注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2、获取数据库连接对象
Connection connection = DriverManager.getConnection("jdbc:mysql://IP:port/databasename", "username", "password");
//3、使用连接对象获取sql语句执行对象
Statement statement = connection.createStatement();
//4、执行sql语句,查询(重点)
String sql = "select * from person";
ResultSet resultSet = statement.executeQuery(sql);//专门执行查询语句,返回ResultSet对象,即查询结果
//5、处理结果集(resultSet结果集对象方法next(),每次指向不同的记录,有数据返回true,否则返回false)
while (resultSet.next()) {
//resultSet结果集对象方法 getXXX("列名") 其中XXX表示数据类型
System.out.println(resultSet.getInt("id") + " " + resultSet.getString("firstName") + " " + resultSet.getString("lastName") + resultSet.getString("address"));
}
System.out.println(resultSet.toString());
//6、释放资源
statement.close();
connection.close();
}
}
(2)查询数据表users,把每一行数据存储在Users类对象中,如果有4行数据,就创建4个对象,并且把对象放到集合中,最后查看集合中的数据
public class JdbcDemo03 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1、注册驱动
Class.forName("com.lmy.domain.Users");
//2、获取数据库连接对象
Connection deployop = DriverManager.getConnection("jdbc:mysql://IP:port/databasename", "username", "password");
//3、获取sql执行对象
Statement statement = deployop.createStatement();
//4、执行sql语句,获取结果集,并创建集合,用于存储Users对象
String sql = "select * from users";
ResultSet resultSet = statement.executeQuery(sql);
ArrayList<Users> usersList = new ArrayList<>();
//5、处理结果集:遍历结果集,把每一条记录存到一个Users对象中,并且把对象放到对象集合中
while(resultSet.next()){
//进入循环,说明有结果,就会有一个users对象
Users users = new Users();
users.setUid(resultSet.getInt("uid"));
users.setUserName(resultSet.getString("userName"));
users.setPassWord(resultSet.getString("passWord"));
users.setNickName(resultSet.getString("nickName"));
usersList.add(users);
}
//6、释放资源
resultSet.close();
statement.close();
deployop.close();
//遍历集合
if(!usersList.isEmpty()){
for (Users users : usersList) {
System.out.println(users);
}
}
}
}
4 PreparedStatement
Statement接口,有一个子接口:preparedStatement,可以将SQL语句存储在对象中,实现多次反复高效执行,所以今后我们推荐使用PreparedStatement对象作为sql语句的执行对象,如下代码是相关的用法,和之前的用法很类似,只是sql语句这回被嵌在sql语句执行对象之中。
public class JdbcDemo04 {
public static void main(String[] args) throws Exception {
//1、注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2、获取数据库连接对象
Connection connection = DriverManager.getConnection("jdbc:mysql://100.75.187.40:4308/cos", "deployop", "GeE8#jlB6h");
//3、通过数据库连接对象获取Statement接口的子接口PreparedStatement\
//拼写sql语句,凡是参数部分不要写死,而是用问号占位符
String sql = "update users set userName=?,passWord=?,nickName=? where uid=?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//指定?的实际参数,使用pst对象方法setObject(第几个问号,实际参数)
preparedStatement.setObject(1,"zhaoliu2");
preparedStatement.setObject(2,"666");
preparedStatement.setObject(3,"赵六");
preparedStatement.setObject(4,4);
//4、执行sql
int row = preparedStatement.executeUpdate();
//5、处理结果集
System.out.println(row);
//6、释放资源
preparedStatement.close();
connection.close();
}
}
5 JDBC工具类的实现与使用
之前写的代码有如下问题:
(1)驱动类的名字、数据库url、用户名、密码这些信息写死在代码里面,不够灵活。
(2)注册数据库驱动这个步骤,重复了,每次访问数据库都要重新注册数据库是没有必要的(注册驱动,只是为了告诉JVM接下来要操作哪种类型的数据库而已)。
(3)获取数据库连接对象、释放资源的步骤是具备通用性的,可以把它们作为方法封装起来,而不是每次都要写具体的代码。
解决思路:
(1)对于原本写死在代码中的信息,可以使用配置文件来提高代码的灵活性。
(2)实现一个工具类,工具类中完成了读取配置文件、驱动注册、获取数据库连接对象、释放资源等操作。
(3)在工具类中,静态代码块部分负责完成:读取配置文件、注册驱动。
(4)在工具类中,分别定义方法,用于“获取数据库连接对象”、“资源释放”。
如下代码为工具类的实现:
public class JdbcUtils {
//定义4个成员变量
private static String driverClass;
private static String url;
private static String user;
private static String password;
//0、静态代码块:读取配置文件、注册驱动
static{
try{
//读取配置文件,获取输入流
InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
//创建集合键值对
Properties properties = new Properties();
//集合IO关联使用
properties.load(inputStream);
//取出集合中的键值对
driverClass = properties.getProperty("driverClass");
url = properties.getProperty("url");
user = properties.getProperty("user");
password = properties.getProperty("password");
//注册驱动
Class.forName(driverClass);
}catch (Exception ex){
ex.printStackTrace();
}
}
//1、获取数据库连接工具方法
public static Connection getConnection() throws SQLException {
//Class.forName("com.lmy.domain.Users"); //注册驱动一次就够,不用每次调用都去重新注册驱动,所以把代码写到静态代码块中
Connection connection = DriverManager.getConnection(url, user, password);
System.out.println(connection);
return connection;
}
//2、资源释放工具方法(加参数,传递哪个关闭哪个,先判断参数是否为空)
public static void close(ResultSet rs, Statement stat, Connection con) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stat != null) {
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
如下代码,使用工具类,实现数据的更新与查询:
/**
* 使用工具类,实现数据的更新和查询
*/
public class JdbcDemo06 {
//测试
public static void main(String[] args) {
//测试更新
update();
//测试查询
select();
}
/**
* 1、实现数据的更新
*/
public static void update() {
//声明变量:据库连接对象、数据库执行对象
Connection con = null;
PreparedStatement pst = null;
try {
//工具类获取数据库连接对象
con = JdbcUtils.getConnection();
//sql语句
String sql = "update users set userName=?,passWord=? where uid=?";
//通过数据库连接对象,获取sql语句的执行对象
pst = con.prepareStatement(sql);
//方法setObject设置参数
pst.setObject(1, "lisi3");
pst.setObject(2, "333333");
pst.setObject(3, 2);
//执行sql
pst.executeUpdate();
} catch (SQLException ex) {
ex.printStackTrace();
} finally {
JdbcUtils.close(null, pst, con);
}
}
public static void select() {
//声明变量:数据库连接对象、数据库执行对象、数据库查询结果集对象
Connection con = null;
PreparedStatement pst = null;
ResultSet rs = null;
try {
//工具类获取数据库连接对象
con = JdbcUtils.getConnection();
//查询语句
String sql = "select * from users";
//获取执行对象
pst = con.prepareStatement(sql);
//没有?占位符的时候就不用设置参数了
//执行语句,获得结果集对象rs,打印查询结果
rs = pst.executeQuery();
while (rs.next()) {
System.out.println(rs.getInt("uid") + "\t" + rs.getString("userName") + "\t" + rs.getString("passWord") + "\t" + rs.getString("nickName"));
}
} catch (SQLException ex) {
ex.printStackTrace();
} finally {
JdbcUtils.close(rs, pst, con);
}
}
}