要面试,因此把以前的笔记整理一遍,嘻嘻,加油java
JDBC编程mysql
JDBC(Java Database Connectiovity,Java数据库链接)是一种执行SQL语句的JavaAPI,程序能够经过JDBC API链接数据库,并使用SQL结构化查询语言完成对数据库的操做,程序员使用JDBC编程时只须要掌握标准的JDBC API 便可,当须要在不一样的数据库之间切换时,只须要更换不一样的数据库驱动类,是面向接口编程的典例应用。ios
JDBC访问数据库时主要完成三个操做:程序员
JDBC驱动: 数据库驱动程序是JDBC程序和数据库之间的转换层,数据库驱动程序负责将JDBC调用映射成特定的数据库调用,有4种类型:JDBC-ODBC桥(最先),本地API驱动,网络协议驱动,本地协议驱动(建议使用,纯java编写)。面试
JDBC API:提供一组用于与数据库进行通讯的接口和类,都定义在java.sql包下。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(); } } } } }