这篇文章主要用来展示jdbc的使用,是为了方便阅读MyBatis源码使用的,为源码分析做一个提前热身;
里面很多关键性的信息在MyBatis源码里面都能找到,本篇不做MyBatis源码的分析,
因为MyBatis源码是一个庞大复杂的工程,不是 一时半会,只言片语就能说完的。
jdbc Demo:
1 public static void main(String[] args) throwsException {2 test1();3 }4
5 public static void test1() throwsException {6 ResultSet rs=null;7 PreparedStatement pst=null;8 Connection conn=null;9 try{10 String sql="select id as sid,name,age,sex from user where id!=? order by id asc ";11 //注册驱动方式1 用反射加载数据库驱动12 //Class.forName("com.mysql.cj.jdbc.Driver");13 //注册驱动方式2 也可以用new MySql的Driver类方式注册驱动14 //new Driver();15 //注册驱动方式3 用反射方式new 一个匿名对象
16 Driver.class.getConstructor().newInstance();17 conn=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/gys?serverTimezone=UTC","root","gys");18 System.out.println("======查询前========");19 DatabaseMetaData dmd=conn.getMetaData();20 System.out.println("数据库名称:"+dmd.getDatabaseProductName());21 System.out.println("数据库版本:"+dmd.getDatabaseProductVersion());22 System.out.println("是否支持事务:"+dmd.supportsTransactions());23 //DriverManager.setLogWriter();
24 pst=conn.prepareStatement(sql);25 //给sql语句的?赋值
26 pst.setString(1,"5");27
28 System.out.println("======查询时========");29 ParameterMetaData pmd=pst.getParameterMetaData();30 System.out.println("参数数量" +pmd.getParameterCount());31 //1表示入参,2表示出入参,3表示出参(主要用于存储过程)
32 System.out.println("第一个参数mode:"+pmd.getParameterMode(1));33
34 //数据库操作方式1
35 boolean res=pst.execute();36 rs=null;37 if(res){38 rs=pst.getResultSet();39 }else{40 System.out.println("返回影响的行数:"+pst.getUpdateCount());41 return;42 }43
44 //数据库操作方式245 //int resCount= pst.executeUpdate();46 //数据库操作方式347 //rs= pst.executeQuery();
48
49 System.out.println("======查询后========");50 ResultSetMetaData rsm=rs.getMetaData();51 System.out.println("列数量:"+rsm.getColumnCount());52 System.out.println("第1列别名:"+rsm.getColumnLabel(1));53 System.out.println("第1列字段名:"+rsm.getColumnName(1));54
55 User user=null;56 while(rs.next()){57 user=newUser();58 user.setId(rs.getLong("sid"));59 user.setName(rs.getString("name"));60 user.setAge(rs.getInt("age"));61 }62 System.out.println("查询数据:"+user.toString());63 }catch(Exception e){64 e.printStackTrace();65 }finally{66 //6.释放资源
67 if(rs!=null){68 rs.close();69 }70 if(pst!=null){71 pst.close();72 }73 if(conn!=null){74 conn.close();75 }76 }77
78 }
执行结果:
demo解析:
驱动的注册(第12,14,16行):
不要被这个高大上的名词迷惑了,其实就是将MySql包中Driver这个类载入虚拟机,然后执行相应的动作。
那么执行的是什么动作呢?
MySql Driver.java看源码:
1 packagecom.mysql.cj.jdbc;2
3 importjava.sql.SQLException;4
5 public class Driver extends NonRegisteringDriver implementsjava.sql.Driver {6
7 static{8 try{9 java.sql.DriverManager.registerDriver(newDriver());10 } catch(SQLException E) {11 throw new RuntimeException("Can't register driver!");12 }13 }14
15
16 public Driver() throwsSQLException {17 //Required for Class.forName().newInstance()
18 }19 }
static块在类载入的时候就会执行,执行的是jdk中DriverManager.registerDriver()注册服务的方法。
Driver也继承了 java.sql.Driver.这也应验的网上到处都说的:jdbc提供接口,数据库厂商提供实现的说法。
从上面的驱动源码分析第12,14,16行三种方式,哪一种注册写法更好呢?
第12行直接通过反射把驱动类载入虚拟机,但是并没有创建任何的对象;
第14行通过new 一个匿名对象来载入驱动类,同时在堆内存中还需要开辟一个内存空间;
第16行也是创建了一个匿名对象,只不过是通过反射的方式,比new 稍微慢那么一丢丢,同样需要虚拟机在堆中开辟内存空间;
因为我们并不需要这个匿名对象,一段时间过后就会被虚拟机给回收掉。
通过分析还是第12行的写法最完美,其实无论用哪种方式注册服务,对于性能和时间上来说都是微乎其微的。
数据库的三种操作方式:
int executeUpdate():执行写sql的操作,比如insert,update,delete;返回受影响的行数。对于创建数据库,删表的操作返回0
ResultSet executeQuery():执行select查询操作的方法。返回查询结果集
boolean execute();包含上面两种操作。查询后返回true,表示pst.getResultSet()有值,否则无值。
==================追加内容=============
jdbc4.0之后的驱动是不需要写的;在JDBC的DriverManager.getConnection()时是第一次使用,有一个静态代码块
这里的101行代码用的是SPI机制,将驱动进行实例化了。