JDBC学习笔记

1.      JDBC概述

1)JDBCjava Data Bace Connectivityjava数据库连接)

2)JDBCjava提供的一套操作数据库的API,基本全是接口和少量类,是一套java操作数据库的标准,主要位于java.sqljavax.sql包中。

3)数据库驱动就是这些借口的实现,每个数据库都有自己的驱动,数据库驱动都是有数据库厂商提供的而不是java提供的。

4JDBC在项目中的位置及作用(如图)

5)我们在项目中与数据库打交道时只要操作JDBC这些接口,所以JDBC也实现的夸数据库的功能,在更换数据库时,只要更换一下数据库驱动就可以了,我们的java代码是不用改变的。

6JDBC是一个接口,不同数据库厂商都去实现这些接口就形成了不同的数据库驱动。与之类似的有Severlet也是java提供的一套接口和标准,不同服务器厂商去实现这些接口从而形成了不同的数据库产品。

 

2.      JDBC简单例子

1)基本步骤

注册驱动(只做一次)

建立连接(Connection

创建执行SQL的语句(Statement

执行SQL语句

处理执行结果(ResultSet

释放资源

      

 

 

 

 

 

 

 

 

 

publicstaticvoid test() throws SQLException{

        //1.注册驱动

        DriverManager.registerDriver(newcom.mysql.jdbc.Driver());

        

        //2.建立连接

Connection conn =DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc","root","");

         

        //3.创建语句

        Statement st =conn.createStatement();

        

        //4.执行SQL语句

        ResultSet rs =st.executeQuery("select * fromuser");

        

        //5.处理执行结果

        while(rs.next()){

            System.out.println(rs.getString("id") + "\t" +rs.getString("name"));

        }

        

         //6.释放资源

        rs.close();

        st.close();

        conn.close();

        

     }

3.  分析JDBC的程序编写步骤和原理

a)        注册驱动

几种方式:

       DriverManager.registerDriver(newcom.mysql.jdbc.Driver());//方式1

System.setProperty("jdbc.drivers","com.mysql.jdbc.Driver");//方式2

    Class.forName("com.mysql.jdbc.Driver");//方式3

 

    注册驱动其实就是将数据库驱动包中的Driver实现类,new一个对象,并将这个对象放进DriverManager类中的一个静态列表中,这个静态列表可以装多个驱动,也就是说我们可以注册多个驱动。

b)   获取连接

String url = "jdbc:mysql://localhost:3306/jdbc";

        String userName = "root";

        String password = "";

Connection conn = DriverManager.getConnection(url,userName,password);

 

url为数据库连接字符串,每个数据库的连接字符串个格式略有不同

获取连接是用DriverManagegetConnection()方法,这个方法是循环那个驱动列表挨个问每个驱动,根据这个url能否建立一个连接,只要有一个能创建连接,就创建并返回一个连接。

4.  规范和风封装JDBC代码

将注册驱动,获取连接,释放数据库资源抽取出放在一个工具类中

publicfinalclass JDBCUtils {

    // 私有化构造方法

    private JDBCUtils() {

 

    }

 

    privatestatic String url = "jdbc:mysql://localhost:3306/jdbc";

    privatestatic String userName = "root";

    privatestatic String password = "";

 

    //静态代码块来注册驱动,保证驱动只注册一次

    static {

       try {

           Class.forName("com.mysql.jdbc.Driver");

       } catch (ClassNotFoundException e) {

           e.printStackTrace();

       }

    }

   

    //获取数据库连接

    publicstatic Connection getConnection() throws Exception{

       return DriverManager.getConnection(url,userName,password);

    }

   

    //释放资源

    publicstaticvoid free(ResultSet rs,Statement st,Connection conn){

       try {

           if(rs != null)

              try {

                  rs.close();

              } catch (SQLException e) {

                  e.printStackTrace();

              }

       }finally{

           try {

              if(st != null)

                  try {

                     st.close();

                  } catch (SQLException e) {

                     e.printStackTrace();

                  }

           }finally{

              if(conn != null)

                  try {

                     conn.close();

                  } catch (SQLException e) {

                     e.printStackTrace();

                  }

           }

          

       }

    }

 

}

5.JDBCUtils用单例实现问题

 

6.JDBC对数据库的CRUD

就是insertupdateselect ,delete语句,select语句用StatementexcuteQuery()方法返回ResultSetinsert,update,delete语句用用StatementexcuteUpdate()方法返回有影响的行数

7.StamentSQL注入的问题

    publicstaticvoid template(String name) throws Exception{

        Connection conn = null;

        Statement st = null;

        ResultSet rs = null;

        try{

            //2.获取连接

            conn = JDBCUtils.getConnection();

            

            //3.创建语句

            st =conn.createStatement();

            

            //4.执行SQL

            rs =st.executeQuery("select * from userwhere name ='"+name+"'");

            

            //5.处理结果集

            while(rs.next()){

               System.out.println(rs.getString("id")+"\t" +rs.getString("name")+"\t"+ rs.getString("birthday")+"\t"+rs.getFloat("money"));

            }

            

            

            

            

        }finally{

           JDBCUtils.free(rs, st, conn);

        }

     }

 

Statement执行Sql语句时有SQL注入的问题,上面的方法如果调用时传个参数为”’ or 1 or ’”,就会将所有的记录都查出来

8.PreparedStatement可以解决Sql注入的问题

    /**

      *  preparedStatement实例

      */

     publicstaticvoidpreparedStatementTemplate(String name) throws Exception{

        Connection conn = null;

         PreparedStatement ps = null;

        ResultSet rs = null;

        try{

            //2.获取连接

            conn = JDBCUtils.getConnection();

            

            //3.创建语句

            ps =conn.prepareStatement("select *from user where name =?");

            

            //4.执行SQL

            ps.setString(1,name);

            rs = ps.executeQuery();

            

            //5.处理结果集

            while(rs.next()){

               System.out.println(rs.getString("id")+"\t" + rs.getString("name")+"\t"+ rs.getString("birthday")+"\t"+rs.getFloat("money"));

            }

            

            

            

            

        }finally{

           JDBCUtils.free(rs, ps, conn);

        }

     }

注意:PreparedStatement执行Sql语句时要注意,要调用不带参数的executeQuery()和executeUpdtae()方法,而不是带参数的,掉带参数的相当于仍然是调的Statement的方法,因为PreparedStatement是继承自Statement的。

9.eclipse中导入的JAR包可以关联源代码

10.JDBC的数据类型和日期问题

 JDBC中的数据类型主要用在两个地方:

1) PreparedStatementsetXXX()方法

2) ResultSetgetXXX()方法

大部分类型很容易理解,只有Date类型有点特殊,JDBC中的Datejava.sql包中的Date,是从java.util包中的Date继承来的。Util包中的date是带时分秒的,而java.sql包中的Date是只有日期的,java.sql包中有DateTime,Timestamp与数据库中日期的的三种类型是一一对应的,他们三个都是继承自util包中的Date类。

11.数据大文本字段

    数据库Varchar类型的字段最长只能存储255个字符,如果字符长度超过255,就要用大文本数据类型clob,不同数据库clob类型的名称不一样,mySql中交Text,有的直接叫clob

具体用到PreparedStamentsetsetCharacterStream()方法和ResultSetgetCharacterStream()getClob()方法。其实数据库中是clob类型时,在PreparedStatementsetString()方法和ResultSetgetgetString()照样可以用。

12. 大的二进制数据类型

    数据库自存储二进制数据时用 blob数据类型。PreparedStatementsetBinaryStream()的方法,ResultSetgetBlob()方法和getBinaryStream()方法。

13.JDBC的其他数据类型

14.解答学员疑问

15.实际项目总如何运用的JDBC

  JDBC查询结果为ResultSet,Dao层中不能讲ResultSet直接返回给业务逻辑层,因为业务逻辑层拿到ResultSet时,ResultSet已经关闭了。所以Dao层查询出的结果ResultSet,我们要封装成JAVA对象后再返回给业务逻辑层。

16.Dao层设计思想和搭建骨架

    数据库每个表都要建一个diMain对象以之相对应,从数据库得到的结果是ResultSet,我们要将ResultSet装换成doMain对象。

17.结合service层讲解Dao层的异常处理

    1)Dao层的异常,一般不处理,直接往上层抛,也就是抛给ServiceC层。

    2Dao层中抛出的异常如果是一种特定的异常如SQLException,那Service方法中调Dao层时,就要处理这些异常,要么catch要么在往上抛,但这样的话Service的代码就写死了,Dao层就不能换别的实现了,别的实现回抛别的异常,那Service的方法还的改,所以在到层我们最好统一抛出一个自定义异常(DaoException,这个异常要继承在RunTimeException。在Service方法中统一处理这一种异常。这样Dao层换实现也不会影响Service 的代码。一定要是RunTimeException因为种异常不要求程序中一定处理,所以不用catch,也不用往上抛,Dao的方法后面就不用必须throws了。方法显得干净好多,也给了Service一个选择,让Service层不是一定要处理Dao层的异常,因为Dao抛出的是运行时异常。这样既达到将异常通知上一层的目的,又让我们的接口不受污染(方法后带有特定的异常)。

18.完成整个DAO层的实现代码

19.JDBC使用DAO工厂模式

    1Service层使用Dao时,要先这么写:

    XXXDao xxxDao = new xxxDaoIml();

    然后再用xxxDao的方法,这样的话,Service层的代码就有写死了,如果Dao层的实现改了,例如改为xxxDaoxxxImpl,Service层的代码必须又要改了,改成:

    XXXDao xxxDao = new xxxDaoxxxImpl();其实用Spring的话就接解决了,因为Spring用的是注入方式。但没有Spring的话,我们用Dao的工厂类实现。实现后Service中就改成这样了,XXXDao xxxDao = XXXDaoFactory.getXXXDao();这样即使Dao的实现换了,我们Service层的代码也不用换了。

DaoFactor用来生产Dao的,至于生产那个Dao,就用Properties文件中配置的来决定。有一个取Properties文件路径的方法,用一个简单方法是,取到类加载器然后用类加载器取,这样就不用写路径了,因为所有文件都被加载到了虚拟机了,只要文件位于ClassPath下就能取到,如下下:

InputStream stream =JDBCTest.class.getClassLoader().getResourceAsStream("aaaa.properties");

20.事务的概念与JDBC事务处理

    1JDBC事务过程如下:

     conn.setAutoCommit(false);

        conn.commit();

        conn.rollback();

21.事务的保存点处理

事务可以回滚到某个点。

SavePoint sp = conn.setSavePoint();

Conn.rollback(sp)

22.JTA分布式事务简单介绍

23.事务的隔离级别

一般有四种:

    1)读未提交

    2)读已提交

    3)可重复读

    4)可串行化

但不同数据库所支持的隔离级别不同,而且不同数据库的默认事务隔离级别也不同。

隔离级别

脏读

不可重复读

幻读

读未提交(Read uncommitted

V

V

V

读已提交(Read committed

x

V

V

可重复读(Repeatable read

x

x

V

可串行化(Serializable

x

x

x

 

 

这样为连接设置事务隔离级别:

conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);

24.JDBC调用存储过程

JDBC调用存储过程的例子:

CallableStatement(从PreperedStatement扩展来)

cs = connection.prepareCall({callpsname(?,?,?)});

cs.registerOutParameter(index,Types.INTEGER);

cs.setXXX(i, xxxx);

cs.executeUpdate();

int id=cs.getInt(index);

25JDBC批处理功能

PreparedStatement.addBatch();

    PreparedStatement.executeBatch();

26.可滚动结果集与分页技术

    1)可滚动的结果集是指,ResultSet不只是能往后滚(rs.next(),而且还可以往前滚(rs.previous(),还可以指定滚到哪一行;

 

可滚动的结果集

    Statement st =

    connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,     ResultSet.CONCUR_UPDATABLE);

    ResultSet rs = st.executeQuery(sql);

    rs.beforeFirst(); rs.afterLast();rs.first();rs.isFirst();rs.last();rs.isLast();

    rs.absolute(9);rs.moveToInsertRow();

 

27.可更新和对更新敏感的结果集

查出结果集后,更新结果集,也会造成数据库的修改。

可更新的结果集

    conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,

                  ResultSet.CONCUR_UPDATABLE);

    rs.updateString("col name", "new value");

    rs.updateRow();

28.数据库的元数据信息

通过数据库连接可以获取数据库的一些信息(数据库元数据)

DatabaseMetaData meta =connection.getMetaData();

DatabaseMetaData中有很多方法,可以获取数据可得各种信息

29.参数的元数据信息

可以获取PreparedStatement的参数的原信息

ParameterMetaData pmd =   preparedStatement.getParameterMetaData();

通过 ParameterMetaData可以获得参数信息。

通过这些特性可以写出比较灵活的JDBC操作的方法。

30.利用结果集元数据将查询结果封装为map

ResultSetMetaData meta = rs.getMetaData();

通过ResultSetMetaData可以获得结果有几列、各列名、各列别名、各列类型等。

 

30.利用结果集元数据将查询结果封装为map

用反射ResultSetMetaData将查询结果读入对象中(简单的O/RMapping

1)SQL语句中列别名和要读入的对象属性名一样;

2)通过ResultSetMetaData获得结果列数和列别名;

3)通过反射将对象的所有setXxx方法找到;

4)3)找到的方法setXxx2)找到的列别名进行匹配(即方法中的xxx于列别名相等);

5)由上一步找到的方法和列别名对应关系进行赋值

Method.invoke(obj,rs.getObject(columnAliasName));

31.Java反射技术入门

32.Java反射的更多细节

33.利用Java反射技术将查询结果封装为对象

34.编写一个基本的连接池来实现连接的复用

DataSource用来取代DriverManager来获取Connection

通过DataSource获得Connection速度很快;

通过DataSource获得的Connection都是已经被包裹过的(不是驱动原来的连接),他的close方法已经被修改。

一般DataSource内部会用一个连接池来缓存Connection,这样可以大幅度提高数据库的访问速度;

连接池可以理解成一个能够存放ConnectionCollection

我们的程序只和DataSource打交道,不会直接访问连接池;

35.对基本连接池进行一些工程细节上的优化

36.通过代理模式来保持用户关闭连接的习惯

37.Java的动态代理及使用该技术完善连接代理

38.标准DataSource接口及数据源的总结介绍

39.如何使用开源项目DBCP(实际项目中常用)

40.DAO中的修改方法提取到抽象父类中

41.使用模板方法设计模式处理DAO中的查询方法

42.使用策略模式对模板方法设计模式进行改进

.

.

.

.

48

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值