前述:
前面我们介绍了Mysql数据库以及SQL语言,我们可以通过命令行或者第三方客户端工具来操作Mysql数据库。
然而,在实际的工作开发过程中,我们是需要整合、关联 java与数据库的,也就是通过 java来访问数据库。
那么,如何实现 java对数据库的访问呢?又是怎么做到 java可以对数据库访问的呢?
-- 让我们先来认识下JDBC,问题便豁然开朗 ...
一、认识JDBC(Java DataBase Connectivity:java数据库连接)
1.1 概述
JDBC是官方(sun公司)定义的一套操作所有关系型数据库的标准接口规范。
我们只需要调用JDBC接口中的方法即可实现访问数据库,但真正操作数据库的是各大数据库厂商根据JDBC接口规范提供的具体实现类,也就是数据库驱动。
- 综上,使用JDBC的好处:
- 程序员如果要开发访问数据库的程序,只需要会调用JDBC接口中的方法即可,不用关注类是如何实现的;
- 使用同一套Java代码,进行少量的修改就可以访问其他JDBC支持的数据库。
1.2 使用JDBC开发使用到的包
会使用到的包 | 说明 |
java.sql | 所有与JDBC访问数据库相关的接口和类 |
javax.sql | 数据库扩展包,提供数据库额外的功能。如:连接池 |
数据库的驱动 | 由各大数据库厂商提供,是对JDBC接口实现的类,需要额外去根据需要下载 |
1.3 JBDC的核心API
接口或类 | 作用 |
DriverManager类 | 1) 管理和注册数据库驱动 2) 得到数据库连接对象 |
Connection接口 | 一个连接对象,可用于创建Statement 和 PreparedStatement对象 |
Statement接口 | 一个SQL语句对象,用于将SQL语句发送给数据库服务器 |
reparedStatement接口 | 一个SQL语句对象,是Statement的子接口 |
ResultSet接口 | 用于封装数据库查询的结果集,返回给客户端Java程序 |
1.4 java代码实现步骤
1. 导入数据库驱动jar包。如:mysql-connector-java-5.1.37-bin.jar
* 复制mysql-connector-java-5.1.37-bin.jar到项目的lib目录下
* 右键-->Add As Library添加jar包成库
2. 加载和注册数据库驱动。-- 告诉程序该使用哪一个数据库驱动jar包
* Class.forName(数据库驱动实现类) 如:Mysql的数据库驱动实现类 com.mysql.jdbc.Driver
/** * com.mysql.jdbc.Driver源码 * java.sql.Driver接口,所有数据库厂商必须实现的接口,表示这是一个驱动 */ public class Driver implements java.sql.Driver { public Driver() throws sQLException { } static { try { DriverManager.registerDriver(new Driver()); //注册数据库驱动 }catch (SQLException var1){ throw new RuntimeException ("can't register driver! "); } } }
注意:从JDBC3开始(或mysql5之后驱动),目前已经普遍使用的版本,可以不用注册驱动而直接使用。Class.forName这句话可以省略。
3. 获取数据库连接对象 Connection
* Connection conn = DriverManager.getConnection("jdbc:mysql://ip地址(域名):端口号/数据库名称[?参数名=参数值]", "用户名", "密码");
/** * DriverManager类中的静态方法 * // 通过连接字符串,用户名,密码来得到数据库的连接对象 * Connection getConnection (String url,String user, String password) * // 通过连接字符串,属性对象来得到连接对象 * Connection getConnection (String url,Properties info) */ /** Connection接口:数据库连接对象 功能: 1. 获取执行sql的对象 * Statement createStatement() * PreparedStatement prepareStatement(String sql) 2. 管理事务: * 开启事务:setAutoCommit(boolean autoCommit) //调用该方法设置参数为false,即开启事务 * 提交事务:commit() * 回滚事务:rollback() */
注意:
- 如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称[?参数名=参数值]
- 不同的数据库连接的URL地址是不同的(如conn获取的就说mysql的地址对象),通用地址格式:
- 协议名:子协议:l服务器名或IP地址:端口号/数据库名[?参数=参数值]
- [?参数=参数值]:比如设置编码格式?characterEncoding=utf8
4. 定义sql语句
5. 获取执行sql语句的对象 Statement
* Statement stmt = conn.createStatement();
/** * PreparedStatement:执行sql的对象 * 1. SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接,会造成安全性问题; * 2. 解决SQL注入问题:使用PreparedStatement对象来解决; * 3. 预编译的SQL:参数使用?作为占位符; * 4. 给占位符?赋值 * 获取执行SQL的对象: * PreparedStatement ps = Connection.prepareStatement(String sql) * 方法: ps.setXxx(参数1,参数2) * * 参数1:?的位置编号 从1 开始 * * 参数2:?的值 * * Statement:用于发送SQL语句给服务器,获取执行SQL的对象 * Statement接口中的方法: * 1. boolean execute(String sql):可以执行任意的sql(了解) * //返回值:影响的行数,可以通过这个影响的行数判断DML语句是否执行成功 返回值>0的则执行成功,反之,则失败。 * 2. int executeUpdate(String sql):执行DML(insert、update、delete)语句、DDL(create,alter、drop)语句 * //返回值:查询的结果集。 * 3. ResultSet executeQuery(String sql):执行DQL(select)语句 * * ResultSet:结果集对象,封装查询结果 * 作用:用于遍历结果集,获取每一条数据记录 * 接口中的方法: * boolean next(): 游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据),如果是,则返回false,如果不是则返回true * getXxx(参数):获取数据 * 1. Xxx:代表数据类型 如:int getInt(), String getString() * 2. 参数 * int:代表列的编号,从1开始。 如: getString(1) * String:代表列名称。 如: getDouble("balance") */
6. 执行sql,接受返回结果(stmt.方法)
7. 处理结果
8. 释放资源 //释放资源一般写在finally代码块中,并需要判断对象是否为null
小贴士:PreparedStatement是Statement接口的子接口,继承于父接口中的所有方法,后期都会使用PreparedStatement来完成增删改查的所有操作
原因:① 可以有效防止SQL注入的问题,效率更高;
② 因为有预先编译的功能,SQL的执行效率更高。
1.5 常用数据类型转换表
SQL类型 | JDBC对应方法 | 返回类型 |
BIT(1) bit(n) | getBoolean() | boolean |
TINYINT | getByte() | byte |
SMALLINT | getShort() | short |
INT | getlnt() | int |
BIGINT | getLong() | long |
CHAR,VARCHAR | getString() | String |
Text(Clob) Blob | getClob getBlob() | Clob Blob |
DATE | getDate() | java.sql.Date 只代表日期 |
TIME | getTime() | java.sql.Timestamp同时有日期和时间 |
TIMESTAMP | getTimestamp() | java.sql.Timestamp同时有日期和时间 |
- java.sql.Date、Time、Timestamp(时间戳),三个共同父类是:java.util.Date
二、抽取JDBC工具类
如果一个功能经常要用到,我们建议把这个功能做成一个工具类,可以在不同的地方重用。
JDBC就符合这样的要求,我们可以把一些共用的代码抽取出来,并通过获取配置文件资源的方式来让代码更具可重用性、可读性、可操作性。
- JDBCUtils工具类
抽取目的:简化书写,让代码更具可重用性、可读性、可操作性。
抽取分析:
- 抽取注册驱动;
- 抽取一个方法获取连接对象;
* 需求:不想传递参数(麻烦),还得保证工具类的通用性。
* 解决:配置文件
jdbc.properties
url=
user=
password=
driver=
3. 抽取一个方法释放资源。
代码实现:
public class JDBCUtils { private static String url; private static String user; private static String password; private static String driver; /** * 文件的读取,只需要读取一次即可拿到这些值。使用静态代码块。 */ static{ //读取资源文件,获取值。 try { //1. 创建Properties集合类。 Properties pro = new Properties(); //获取src路径下的文件的方式--->ClassLoader 类加载器 ClassLoader classLoader = JDBCUtils.class.getClassLoader(); URL res = classLoader.getResource("jdbc.properties"); String path = res.getPath(); //2. 加载文件 pro.load(new FileReader(path)); //3. 获取数据,赋值 url = pro.getProperty("url"); user = pro.getProperty("user"); password = pro.getProperty("password"); driver = pro.getProperty("driver"); //4. 注册驱动 Class.forName(driver); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } /** * 获取连接 * @return 连接对象 */ public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url, user, password); } /** * 释放资源 * @param stmt * @param conn */ public static void closeSC(Statement stmt, Connection conn){ if( stmt != null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if( conn != null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } /** * 释放资源 * @param stmt * @param conn */ public static void closeRSC(ResultSet rs, Statement stmt, Connection conn){ if( rs != null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if( stmt != null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if( conn != null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
三、JDBC操作事务
之前我们已经使用Mysql的命令来操作事务,那么现在认识了JDBC后,如何通过JDBC来操作事务呢?
1.1 通过Connection对象来管理事务
Connection接口中有与事务相关的方法,可以通过这些方法来操作管理事务。
相关方法 | 操作 |
void setAutoCommit(boolean autoCommit) | 调用该方法设置参数为false,表示关闭自动提交,即开启事务 |
void commit() | 提交事务 |
void rollback() | 回滚事务 |
1.2 开发步骤
- 获取连接:Connection conn = JDBCUtils.getConnection();
- 开启事务:conn.setAutoCommit(false);
- 获取执行sql对象:conn.prepareStatement(sql);
- 执行sql,返回结果;
- 提交事务/回滚事务;
- 关闭资源。
1.3 代码实现
public class JDBCAutoCommit { public static void main(String[] args) { Connection conn = null; PreparedStatement pstmt1 = null; PreparedStatement pstmt2 = null; try { //1.获取连接 conn = JDBCUtils.getConnection(); //2.开启事务 conn.setAutoCommit(false); //3.定义sql String sql1 = "... ..."; String sql2 = "... ..."; //4.获取执行sql对象 pstmt1 = conn.prepareStatement(sql1); pstmt2 = conn.prepareStatement(sql2); //5.设置参数 ... ... //6.执行sql pstmt1.executeUpdate(); // 手动制造异常 int i = 3/0; pstmt2.executeUpdate(); //7.提交事务 conn.commit(); } catch (Exception e) { try { if(conn != null) { //8.事务回滚 conn.rollback(); } } catch (SQLException e1) { e1.printStackTrace(); } }finally { //9.关闭资源 JDBCUtils.closeSC(pstmt1,conn); JDBCUtils.closeSC(pstmt2,null); } } }