要面试,所以把之前的笔记整理一遍,嘻嘻,加油
JDBC编程
JDBC(Java Database Connectiovity,Java数据库连接)是一种执行SQL语句的JavaAPI,程序可以通过JDBC API连接数据库,并使用SQL结构化查询语言完成对数据库的操作,程序员使用JDBC编程时只需要掌握标准的JDBC API 即可,当需要在不同的数据库之间切换时,只需要更换不同的数据库驱动类,是面向接口编程的典例应用。
JDBC访问数据库时主要完成三个操作:
JDBC驱动: 数据库驱动程序是JDBC程序和数据库之间的转换层,数据库驱动程序负责将JDBC调用映射成特定的数据库调用,有4种类型:JDBC-ODBC桥(最早),本地API驱动,网络协议驱动,本地协议驱动(建议使用,纯java编写)。
JDBC API:提供一组用于与数据库进行通信的接口和类,都定义在java.sql包下。
Java.sql包常用接口和类
使用JDBC API中的类或者接口访问数据库时,容易引发SQLException异常,属于检查性异常。需要放在try……catch语句里,对于DriverManager来讲,要用到ClassNotFoundException异常。
DriverManager类:是数据库驱动管理类,用于管理一组JDBC驱动程序的基本服务,应用程序和数据库之间可以通过DriverManager建立连接,
DriverManager常用静态方法
Connection接口:用于连接数据,每个Connection代表一个数据库连接会话,一个应用程序可以与单个或者多个数据库连接,通过DriverManager类的getConnection()方法可以返回同一个Connection对象,该对象提供创建SQL的语法,完成基本SQL操作
Connection的常用方法
Statement接口:一般用于执行SQL语句,在JDBC中要执行SQL查询语句的方式有
三种方式。Statement和PreparedStatement和CallableStatement三个接口具有依次继承关系。
Statement接口常用方法
ResultSet接口:用于封装结果集对象,该对象包含访问查询结果的方法,使用Statement中的executeQuery()方法可以返回一个ResultSet结果集对象(f封装了所有查询条件的记录),ResultSet具有指向当前数据行的游标,并提供了许多方法来操作结果集中的游标,提供getXXX()方法对结果集进行访问。调用next()方法游标会向下移动,
ResultSet接口常用方法
数据库环境搭建:
数据库访问:使用JDBC访问数据库步骤:
Connection conn = DriverManager.getConnection(String url,String user,String pass);
mysql:DriverManager.getConnection("jdbc:mysql://localhost:3306/shop", "root","mysql");
oracle:DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl","sys as sysdba","oracle");
Statement接口:
execute()方法可以执行任何SQL语句,返回值为布尔型表示是否返回了ResultSet对象,true时使用Statement的getResultSet()方法来获取execute()方法执行SQL语句返回的ResultSet对象;false时使用getUpdateCount()方法获取受影响得行数。
executeUpdate()和executeLargeUpdate():用于执行DML和DDL语句,返回对应的行数和0;当DML语句影响的记录超过Integer.MAX_VALUE时,使用executeLargeUpdate(),类型为long;
PreparedStatement接口:
PreparedStatement对象包含的SQL语句进行预编译,需要多次执行相同的SQL语句时,编译好的语句比Statement对象快。可以执行动态的SQL语句,即在SQL 语句中提供参数,动态SQL语句中用?作为动态参数的占位符。用setXXX()的方法通过占位符的索引完成对参数的赋值。
例:String insterSql = "INSERT INTO LIRUILONG.my_tests VALUES(?,?)";
PreparedStatement ps = conn.prepareStatement(insterSql);
ps.setInt(1,4);
ps.setString(2, "李瑞龙");
CallableStatement接口:
JDBC提供CallableStatement接口,用于执行数据库的储存过程,该接口可以处理一般的SQL 语句,也可以处理以三种带参数(IN ,OUT,IN OUT)的SQL储存过程,使用Connection类的prepareCall(String sql)方法可以创建一个CallableStatement对象,方法的参数可以是一个调用存储过程的字符串,cast = conn.prepareCall("{call LIRUILONG.addSub(?,?)");对CallableStatement的SQL语句执行一般用execute().
调用存储过程的SQL:“{call 存储过程名[(参数占位符?)]}”、、有返回值的:“{参数占位符?=call 存储过程名[(参数占位符?)]}”
CallableStatement接口通过setXXX()方法对IN参数进行赋值,
通过registerOutParameter(1, sql.Types.)方法对OUT参数进行类型注册,第二个参数通常使用java.sql.Types静态常量指定。
检索结果的获取通过getXXX()方法获取OUT和IN OUT参数的值,
对于IN OUT 参数的值来讲需要先使用setXXX()方法对参数进行设置,然后使用registerOutParameter()进行类型注册,最后使用getXXX()方法来获取检索结果
数据库访问优化:
即编写一个数据库访问工具类DBUtil,用于提供访问数据库时所用到的连接,查询等
编写属性文件:存放连接数据库的参数信息,在项目的更目录下创建一个config子目录。并添加一个属性文件oracle.properties,该文件以键-值对的形式保存连接Oracle的配置信息。在读取配置文件的配置信息时,需要编写一个Config配置类,在给类中通过java.util.Properrties类的get()方法来获取指定的“键”所对应的值。
编写DBUtil工具类。将SQL语句与参数包装传递
使用DBUtil工具类。
集元数据
集元数据(Meta Data)是有关数据库和表结构的信息,JDBC提供了获取这些信息的DatabaseMetaData和ResultSetMetaData接口。
DatabaseMetaData接口:DatabaseMetaData接口主要用于获取数据库相关信息,如数据库的所有表的列表,系统函数,关键字,数据库产品名以及驱动类型。DatabaseMetaData对象通过getMetaData()方法进行获取。DatabaseMetaData接口提供大量获取信息的方法,这些方法可分为两大类:
DatabaseMetaData
ResultSetMetaData接口:用于获取结果集的结构信息,通过ResultSet的getMetaData()方法来获取对应的ResultSetMetaData对象
ResultSetMetaData的常用方法
事务处理:
事务是保证底层数据完整的重要手段由一步或几步数据库操作序列注组成的逻辑执行单元。事务具有ACID四个特性:
事务处理包括事务提交,终止和回滚,事务提交分显式提交(commit)和自动提交,事务终止指未能成功完成事务,执行中断,事务回滚有显式回滚(rollback)和自动回滚(系统错误或强行退出)
JDBC对事务操作由Connection提供:
开启事务,执行任意多条DML语句,执行成功提交事务,失败回滚事务,Connection在默认情况下会自动提交,及事务是关闭的,一条SQL语句执行后,系统调用commit()方法提交数据库,无法回滚,使用Connection的setAutoCommit()方法可以开启关闭自动提交模式(事务),该方法为布尔型,参数false为关闭自动提交,反之打开自动提交。
当程序遇到未处理的SQLException异常,都会自动回滚,当捕获该异常时,则需要在处理块中显示回滚。
保存点操作:
批量更新:
---------------------
JDBC工具类
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/project jdbc.user=root jdbc.password=123456 jdbc.datasource.size=10
package com.lirong.sparkproject.constant; public interface Constants { /** * 数据库相关常量 */ String JDBC_DRIVER = "jdbc.driver"; String JDBC_URL = "jdbc.url"; String JDBC_USER = "jdbc.user"; String JDBC_PASSWORD = "jdbc.password"; String JDBC_DATASOURCE_SIZE="jdbc.datasource.size"; }
import java.io.InputStream; import java.lang.reflect.Method; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Properties; import com.lirong.sparkproject.constant.Constants; public abstract class JDBCHelper { //配置对象 private static Properties prop=new Properties(); /* * jdbc变量 */ static String driver=null; static String url=null; static String user=null; static String password=null; //thread封装Connection对象 static ThreadLocal<Connection> thread=new ThreadLocal<Connection>(); //唯一空构造器私有化,不允许外部创建对象 private JDBCHelper() {} /** * 静态代码块为jdbc变量赋值 * 因为静态代码块最先执行,所以调用getConnection()方法时, * 该方法内部的jdbc变量就完成了赋值操作 */ static { try { //动态获取配置文件的路径 InputStream in=JDBCHelper.class.getClassLoader().getResourceAsStream("my.properties"); prop.load(in);//加载键值对信息 /* * Constants常量接口中保存了很多常量,这些常量的值就是配置文件k-v数据的键 * */ driver=prop.getProperty(Constants.JDBC_DRIVER); url=prop.getProperty(Constants.JDBC_URL); user=prop.getProperty(Constants.JDBC_USER); password=prop.getProperty(Constants.JDBC_PASSWORD); /* * 加载驱动,静态代码块只执行一次,驱动只加载一次(加载驱动很耗性能的) */ Class.forName(driver);//加载驱动 } catch (Exception e) { e.printStackTrace(); } } /** * 通过本方法客获取一个MySQL数据库的Connection对象 * * @return Connection对象 */ public static Connection getConnection() { Connection con = thread.get(); if(con==null) { try { con = DriverManager.getConnection(url, user, password); thread.set(con); } catch (SQLException e) { e.printStackTrace(); } } return con;//返回jdbc连接 } /** * 本方法中调用Date类型变量的setter方法时使用的是java.sql.Date, * 所以实体类在声明Date类型变量时一定声明成java.sql.Date * 至少Date类型变量对应的setter方法的形参必须是java.sql.Date,否则报错 * * 查询完毕后,使用者通过JDBCHelper.getConnection()获取连接对象,并关闭它 * 外部获取的连接对象与本方法使用的连接对象,在同一线程类,是同一个对象 * * @param sql 要执行的查询语句 * @param t 实体类对象 * @param objs SQL语句中的参数 * @return 装有实体类对象的list集合 */ public static <T> List<T> executeQuery(String sql,T t,Object...objs){ //声明jdbc变量 List<T> list=new ArrayList<>(); Connection conn = null; PreparedStatement ps =null; ResultSet rs =null; try { conn = JDBCHelper.getConnection(); ps = conn.prepareStatement(sql); //给占位符赋值 if(objs!=null) { for(int i=0;i<objs.length;i++) { ps.setObject((i+1), objs[i]); } } //执行sql语句 rs = ps.executeQuery(); //获取结果集中字段的所有信息 ResultSetMetaData rm = rs.getMetaData(); int columnCount = rm.getColumnCount();//获取字段数 //遍历结果集 while(rs.next()) { Class<? extends Object> cla = t.getClass();//获取类对象 T newInstance=(T)cla.newInstance();//获取类的对象 //一个for循环封装一条记录的所有值 for(int i=1;i<=columnCount;i++) { String columnName = rm.getColumnName(i);//获取字段名 //获取字段对应的setter方法 String methodName="set"+columnName.substring(0, 1).toUpperCase()+columnName.substring(1); String columnClassName = rm.getColumnClassName(i);//获取字段java类型的完全限定名 //创建方法对象 Method method = cla.getDeclaredMethod(methodName, Class.forName(columnClassName)); method.invoke(newInstance,rs.getObject(columnName));//调用setter方法,执行对象属性赋值 } list.add(newInstance);//将对象加入集合 } } catch (Exception e) { e.printStackTrace(); }finally { //关流 JDBCHelper.close(ps,rs); } return list; } /** * 该方法封装了MySQL数据库的DML操作 * 如果要实现事务: * 事务的开启,关闭,回滚,及连接对象的关闭等操作 * 使用者通过JDBCHelper.getConnection()获取连接对象,通过连接对象并在外部声明 * 外部获取的连接对象与本方法使用的连接对象,在同一线程类,是同一个对象 * * @param sql 要执行的SQL语句 * @param objs SQL语句中的参数 * @return 成功执行返回影响的记录条数,否则返回0 * @throws SQLException */ public static Integer executeDML(String sql,Object...objs) { //声明jdbc变量 Connection conn =null; PreparedStatement ps =null; Integer i =0; try{ conn = JDBCHelper.getConnection(); ps = conn.prepareStatement(sql); //给占位符赋值 if(objs!=null) { for(int j=0;j<objs.length;j++) { ps.setObject((j+1), objs[j]); } } //执行SQL语句 i = ps.executeUpdate(); }catch(SQLException e) { e.printStackTrace(); }finally { //关流 JDBCHelper.close(ps); } return i; } /** * 关流的方法,接收任意多个任意类型的流对象 * 如果关闭的流对象有关闭的先后顺序 * 请将要先关闭的流对象放在前方 * * 所有流对象的顶级父接口都是AutoCloseable * @param t 要关闭的流对象,可以是一个或多个(也可以是零个) * */ private static <T>void close(T...t){ //循环关流 for(T tmp:t) { //关闭流对象 if(tmp instanceof AutoCloseable) { try { ((AutoCloseable)tmp).close(); } catch (Exception e) { e.printStackTrace(); } } } } }
原文:https://www.cnblogs.com/liruilong/p/12257099.html