JDBC全称Java database connectivity,是Java和数据库连接的一个桥梁,是一种使用Java操作数据库的规范。
1、因为访问数据库需要用到专门的第三方工具类的jar包,所以我们在使用时需要引入外部jar包,以IDEA编辑器和mysql为例,这里我们需要使用Maven工程,新建Maven工程,在maven官网(https://mvnrepository.com/)搜索mysql,选择 MySQL Connector/J,选择下载量最多的5.1.38版本复制代码到pom.xml文件29行标签dependency里,就会把相应的jar包导入到相应工程内了。
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
2、定义数据库常量,共4个点
1、数据库驱动:driver=com.mysql.jdbc.Driver
2、连接数据库的url:url=jdbc:mysql://192.168.221.***:3306/kb10mysqltestdb?useUnicode=true&characterEncoding=utf8&useSSL=true
3、数据库登录名:username=******
4、数据库登陆密码:password=******
这里面数据库常量一般建议放在resources过的配置文件里,把数据库常量以键值对的形式写进去,方便后续维护
3、新建一个BaseConfig类,写一个初始化各个配置项的方法,然后用构造器调取该方法作为访问该类的初始化参数,因为涉及到登陆密码等,该类的访问权限可以设置的低一些,尽量不用public。
4、初始化各个配置的方法中,要用到Tread.currentTread().getContextClassLoader().gerResource(“file_name”).getPath()方法获取到文件路径,然后使用专门读取配置文件的类Properties(new一个对象)下面的load方法读取这个这个路径下的方法;接下来,使用properties类下的getProperty方法依次读取“url”“driver”“username”“password”;最后把得到的参数传给当前对象。
5、创建一个注册驱动的getCon()连接方法,把初始化进来的参数传到DriverManager.getConnection方法里;
6、创建一个关闭资源释放资源的close()方法
代码如下:
package cn.kb10.jdbc2;
import java.io.FileReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
class BaseConfig {
//想隐藏的话,就写内部类
private class Config{
String driver;
String url;
String username;
String password;
public Config(String driver, String url, String username, String password) {
this.driver = driver;
this.url = url;
this.username = username;
this.password = password;
}
}
private Config config;
//构造方法也不想被人看到,用代码块
{
try {
init();
//装载驱动
Class.forName(config.driver);
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
//初始化,读取配置信息
private void init() throws Exception {
String path = Thread.currentThread().getContextClassLoader().getResource("datasource.properties").getPath();
Properties pro = new Properties();
pro.load(new FileReader(path));
String url = pro.getProperty("url");
if (null==url){
throw new Exception("缺少url配置项异常");
}
String driver = pro.getProperty("driver","com.mysql.jdbc.Driver");
String username = pro.getProperty("username","root");
String password = pro.getProperty("password","root");
this.config = new Config(driver,url,username,password);
}
protected Connection getCon() throws SQLException {
return DriverManager.getConnection(config.url,config.username,config.password);
}
protected void close(AutoCloseable...acs){
for (AutoCloseable ac : acs) {
if (null!=ac){
try {
ac.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
7、新建一个继承于BaseConfig的子类,这个子类就3个方法,一个是预编译的方法(这里可以理解为写好的、只缺一个回车键、待执行的sql语句),一个是增删改的方法,一个是查询的方法。
8、首先先写一下预编译的方法,这里用到了PrepareStatement接口,既然是预编译,在使用时就要传入相应的参数,传入哪些参数呢?第一个是之前之前要注册连接上数据库吧,也就是getCon方法执行后的结果;连接上之后,要执行语句吧,第二个参数就是sql语句;第三个参数是是一个通配符数组,就是在sql语句执行时设置where子句的条件,比如说查询学号为XX的成绩,加上这个参数后,可以通过直接控制这个通配符数组来更新条件,当然也可以不要,直接在sql语句里修改,就是麻烦了些不够清晰,也没啥问题。多说一句,这个参数可以是整数也可以是字符串的,所以在参数时设置为Object类型的,通过setObject方法自动识别为对应的数据类型,在使用setObject时,需要注意下遍历数组元素时,mysql是从1开始的,因此索引是从1开是,也就是i+1。输入这几个参数后,直接返回即可。
9、先写增删改方法。增删改的返回值一般是affected n rows,因此我们返回int类型的值。这里我们的参数是sql语句和控制where子句范围的动态数组。首先我们定义一个连接器和预编译器,初始化为null,然后分别执行对应的方法,注册驱动和预编译。到这里基本就结束了,直接返回预编译后更新表格的条数。最后调用close方法倒序依次关闭调用的预编译器和连接器,释放资源。
10、再写查询方法,查询的方法和增删改一样,但是在mysql里返回的结果一般来说是个n*n的二维数组,而在executeQuery方法里返回的是一个ResultSet的结果集对象,这时候我们需要把结果集的内容依次放到二维数组里输出。前面的写法和增删改基本上一样,只不过多了一个结果集的初始化。ResultSet是一个接口,有点像是一个集合。把结果集对象输出为二维数组,首先二维数组的行数是不能确定的,但是列数时可以确定的(这里我们就先不严谨的把ArrayList集合说成为数组,好理解一些),因此我们调用结果集的getMetaDate再调用getColumnCount方法获取总的列数,然后定义一个嵌套ArrayList集合。然后通过结果集的next()方法遍历结果集,对遍历的每一个结果,都放到内层的集合里;一旦结果集读取到列数的最大值,则把这一行(内层集合)作为一个元素赋值给外层元素。等全部读完了,就可以返回这个二维数组了。最后依次倒序关闭结果集、预编译器、连接器。
代码如下:
package cn.kb10.jdbc2;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public final class BaseDao extends BaseConfig{
private PreparedStatement getPst(Connection con,String sql, Object...params) throws SQLException {
PreparedStatement pst = con.prepareStatement(sql);
if (params.length>0){
for (int i = 0; i < params.length; i++) {
pst.setObject(i+1,params[i]);
}
}
return pst;
}
public Result exeNonQuery(String sql,Object...params){
Connection con = null;
PreparedStatement pst = null;
try {
con = getCon();
pst = getPst(con,sql,params);
return Result.succeed(pst.executeUpdate());
} catch (SQLException e) {
return Result.fail();
}finally {
close(pst,con);
}
}
public Result exeQuery(String sql,Object...params){
Connection con =null;
PreparedStatement pst = null;
ResultSet rst = null;
try {
con = getCon();
pst = getPst(con,sql,params);
rst = pst.executeQuery();
List<List<String>> data = new ArrayList<>();
if (null!=rst&&rst.next()){
final int CC = rst.getMetaData().getColumnCount();
do{
List<String> row = new ArrayList<>(CC);
for (int i = 1; i <=CC ; i++) {
row.add(rst.getObject(i).toString());
}
data.add(row);
}while (rst.next());
}
return Result.succeed(data);
}catch (Exception e){
return Result.fail();
}finally {
close(rst,pst,con);
}
}
}
package cn.kb10.jdbc2;
public final class Result<T> {
//统一格式的类
private boolean err;
private T data;
//方法集泛型
public static <T> Result succeed(T data){
return new Result(false,data);
}
public static Result fail(){
return new Result(true,null);
}
private Result(boolean err, T data) {
this.err = err;
this.data = data;
}
public boolean isErr() {
return err;
}
public T getData() {
return data;
}
}