JDBC学习笔记

1.1  JDBC:

1.1.1     JDBC的概述:

什么是JDBC:

JDBC:(Java DataBaseConnectivity Java数据库连接).

* 是一种用于执行SQL语句的Java 的API.可以为多种关系型数据库提供统一的访问.它是由一组使用Java语言编写的类或接口组成.

JDBC的功能:

JDBC功能主要就是使用Java语言连接到数据库.

哪些地方使用JDBC:

任意一个应用:

* 学生选课:

* OA:

* 系统都需要与数据库进行交互.都需要使用JDBC.

什么是驱动:

驱动:两个设备之间的通信桥梁.

* Java语言要连接数据库必须使用数据库的驱动.

* 各个数据库的生产商提供数据库的驱动.使用Java连接各种数据库.需要了解各个数据库的驱动.增加Java程序员压力.

* SUN公司与各个数据库生产商协商.由SUN公司提供一套统一的规范.由各个数据库的生产商提供这套规范的实现.

* SUN公司提供了一组接口.各个数据库生产商提供了这套接口的实现.(这组规范就是JDBC规范.)

1.1.2     JDBC的快速入门:

JDBC开发步骤:

步骤1:搭建开发环境,引入数据库的驱动.

步骤2:在程序中加载数据库驱动.

步骤3:获得数据库连接.

步骤4:编写SQL.执行SQL.

步骤5:释放资源.

JDBC的入门案例:

public void demo1() throws SQLException{

     // 1.加载驱动

     DriverManager.registerDriver(new Driver());

     // 2.获得连接.

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

     // 3.编写SQL并且执行SQL.

     String sql = "select * from user";

     Statement statement = connection.createStatement();

     // 结果集:查询后的数据的封装.

     ResultSet rs = statement.executeQuery(sql);

     // 遍历:

     while(rs.next()){

         int id = rs.getInt("id");

         String username =rs.getString("username");

         String password = rs.getString("password");

         System.out.println(id+"    "+username+"    "+password);

     }

     // 4.释放资源.

     rs.close();

     statement.close();

     connection.close();

}

1.1.3     JDBC的API的详解:

DriverManager:驱动的管理类.

主要的作用:

* 一、注册驱动:(加载驱动)

* registerDriver(Driver driver);

***** 在实际开发中很少使用registerDriver注册驱动?

* 1.使用这个方法注册驱动,使程序依赖了具体的驱动.

* import com.mysql.jdbc.Driver;

* 2.这个方法会导致驱动被注册两次:---查看Driver类的源码.

查看源码可以看到:在静态代码块中注册了驱动.

静态代码块何时执行?:在类加载的时候.

static {

     try {

         java.sql.DriverManager.registerDriver(newDriver());

     }catch (SQLException E) {

         thrownew RuntimeException("Can't register driver!");

     }

}

***** 解决这两个问题:

反射:  Class.forName(“com.mysql.jdbc.Driver”);

 

 

* 二、获得连接:

* getConnection(String url,String username,String password);

* url        :数据库连接的路径.

* username  :连接数据库用户名.

* password  :连接数据库密码.

 

***** url的写法:

* jdbc:mysql://localhost:3306/web017

* jdbc       :连接数据库协议.

* mysql      :JDBC协议的一个子协议.

* localhost:数据库服务器主机名.

* 3306       :mysql数据库服务器的端口号.

* web017    :数据库名称.

* url简写为  :jdbc:mysql//localhost:3306/web017默认连接本地的mysql服务器默认的端口号3306.

* 简写   :jdbc:mysql:///web017

Connection:连接对象.

Connection由DriverManager创建的.代表的是一个连接的对象.

主要有两个作用:

* 一、创建执行SQL语句的对象.

 

* 创建Statement对象.

* 创建PreparedStatement对象.对SQL进行预编译.(防止SQL注入的漏洞.)

 

* 创建CallableStatement.用来执行数据库中存储过程.

* 二、进行事务的管理:

 

* 设置事务不自动提交.

* 事务提交.

* 事务回滚.

Statement:执行SQL的对象.

Statement对象由Connection对象创建的.代表是可以运行SQL的类.

主要有两个作用:

* 一、执行SQL语句.

 

* 执行查询语句.执行select语句.返回了一个ResultSet对象.代表查询结果的表格数据.

* 执行更新语句.执行update、insert、delete语句的时候.返回int类型数据.int类型的数据代表的是影响的行数.

* 执行SQL语句.执行select、insert、update、delete语句.返回的是boolean值.如果返回的结果为ResultSet.那么boolean值为true.如果返回的是更新的记录数.那么boolean就为false.

 

 二、执行批处理.

 

* 将SQL添加到批处理中.

 

* 清空批处理.

 

* 执行批处理.

ResultSet:结果集.

ResultSet对象由Statement对象中executeQuery(String sql);返回的.ResultSet对象代表的是select查询后的结果.

* 在ResultSet内部维护了一个指向标哥数据行的游标Cursor,初始化时候,游标在第一行之前的位置.调用ResultSet中next()方法.可以使游标指向具体的数据行,进而调用方法获得该行的数据.

方法:

 

* 向下移动光标.

* 获得结果集中整形数据.

* 获得结果集中字符串类型的数据:

 

。。。。。。

...

遍历结果集:

*    while(rs.next()){

         int id = rs.getInt("id");

         String username =rs.getString("username");

         String password =rs.getString("password");

         System.out.println(id+"    "+username+"    "+password);

     }

获得结果集中的数据:

* int id = rs.getInt("id");

String username = rs.getString("username");

String password = rs.getString("password");

 

如果结果集中只有一条记录:

* if(rs.next()){

...

}

滚动结果集:(了解)

结果集默认的情况下只能向下而且不可以在结果集上进行修改记录.

* MYSQL数据库结果集可以滚动.

* 在Statement被创建的时候:

* Statement createStatement(int resultSetType,intresultSetConcurrency);

* resultSetType                   :结果集类型

* TYPE_FORWARD_ONLY         :结果集只能向下.

* TYPE_SCROLL_INSENSITIVE        :结果集可以滚动.不允许进行修改结果集

* TYPE_SCROLL_SENSITIVE     :结果集可以滚动.允许在修改结果集.

 

* resultSetConCurrency  :结果集并发策略.

* CONCUR_READ_ONLY          :结果集不可以修改

* CONCUR_UPDATABLE          :结果集可以修改.

 

* 组合:

* TYPE_FORWARD_ONLY     CONCUR_READ_ONLY    :结果集只能向下而且不可以进行修改.(默认值)

* TYPE_SCROLL_INSENSITIVE   CONCUR_READ_ONLY:结果集可以滚动,但是不可以修改结果集.

* TYPE_SCROLL_SENSITIVECONCUR_UPDATABLE    :结果集可以滚动,而且可以修改结果集.

 

案例:

public void demo2() throwsClassNotFoundException, SQLException {

     // 1.加载驱动

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

     // 2.获得连接

     Connection conn =DriverManager.getConnection("jdbc:mysql:///web017",

             "root","123");

     // 3.执行SQL.

     String sql = "select* from user";

     Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,

             ResultSet.CONCUR_UPDATABLE);

     ResultSet rs =stmt.executeQuery(sql);

     // 直接定位到某一行:

     rs.absolute(3);

     rs.updateString("username","eee");

     rs.updateRow();

     // 4.释放资源

     rs.close();

     stmt.close();

     conn.close();

}

1.1.4     JDBC的资源释放:

资源的释放是非常重要,我们写的资源释放的代码,是非常不规范!!!

尤其Connection对象是非常稀有!代表的是数据库连接对象.安装MYSQL的数据库时候,MYSQL有最大连接数量.如果达到MYSQL的最大连接数量,而且Connection都没有被释放.其他人连接不到数据库.

如果Connection不能及时,正确关闭.极易导致系统宕机.Connection的使用原则:尽量要晚创建,尽量早释放!!!

为了确保释放的代码能够得到执行,资源释放的代码一定要放在finally代码块.

 

资源释放的一段标准代码:

         // 4.释放资源.

         if (rs != null) {

             try {

                 rs.close();

             } catch (SQLException e) {

                 e.printStackTrace();

             }

             rs = null; // 为了让JVM垃圾回收更早回收该对象.

         }

 

         if (stmt != null) {

             try {

                 stmt.close();

             } catch (SQLException e) {

                 e.printStackTrace();

             }

             stmt = null;

         }

 

         if (conn != null) {

             try {

                 conn.close();

             } catch (SQLException e) {

                 e.printStackTrace();

             }

             conn = null;

         }

1.1.5     JDBC完成CRUD的操作:

参见JDBCDemo2案例.

1.1.6     JDBC工具类的抽取:

public class JDBCUtils{

 

private static final String DRIVERCLASS;

private static final String URL;

private static final String USERNAME;

private static final String PASSWORD;

 

static {

     // 解析属性文件:Properties.

     /* Properties properties = new Properties();

     // 获得代表属性文件的输入流:

     // 使用类的加载器获得属性文件的输入流:

     InputStream is =JDBCUtils.class.getClassLoader().getResourceAsStream(

             "jdbc.properties");

     // 加载属性文件:

     try {

         properties.load(is);

     } catch (IOException e) {

         e.printStackTrace();

     }

 

     DRIVERCLASS = properties.getProperty("jdbc.driverClass");

     URL = properties.getProperty("jdbc.url");

     USERNAME = properties.getProperty("jdbc.username");

     PASSWORD = properties.getProperty("jdbc.password");*/

    

     // 国际化有关:

     DRIVERCLASS =ResourceBundle.getBundle("jdbc").getString("jdbc.driverClass");

     URL =ResourceBundle.getBundle("jdbc").getString("jdbc.url");

     USERNAME =ResourceBundle.getBundle("jdbc").getString("jdbc.username");

     PASSWORD =ResourceBundle.getBundle("jdbc").getString("jdbc.password");

}

 

/**

 * 注册驱动的方法:

 */

public static void loadDriver() {

     try {

         Class.forName(DRIVERCLASS);

     } catch (ClassNotFoundException e) {

         e.printStackTrace();

     }

}

 

/**

 * 获得连接的方法

 */

public static Connection getConnection() {

     Connection conn = null;

     try {

         // 加载驱动

         loadDriver();

         conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);

     } catch (Exception e) {

         e.printStackTrace();

     }

     return conn;

}

 

/**

 * 释放资源的代码

 */

public static void release(Statement stmt, Connection conn) {

     if (stmt != null) {

        try {

             stmt.close();

         } catch (SQLException e) {

             e.printStackTrace();

         }

         stmt = null;

     }

 

     if (conn != null) {

         try {

             conn.close();

         } catch (SQLException e) {

             e.printStackTrace();

         }

         conn = null;

     }

}

 

public static void release(ResultSet rs, Statement stmt, Connectionconn) {

     if (rs != null) {

         try {

             rs.close();

         } catch (SQLException e) {

             e.printStackTrace();

         }

         rs = null;

     }

 

     if (stmt != null) {

         try {

             stmt.close();

         } catch (SQLException e) {

             e.printStackTrace();

         }

         stmt = null;

     }

 

     if (conn != null) {

         try {

             conn.close();

         } catch (SQLException e) {

             e.printStackTrace();

         }

         conn = null;

     }

}

}

1.1.7     JavaEE的模式-DAO模式:

DAO:Data Access Object.数据访问对象.

* DAO:DAO中封装对数据源的单个操作,需要对外提供一组接口供业务层访问.访问DAO的时候传递一个Java对象.

* 使用DAO的模式完成CRUD的操作.

1.1.8     DAO的模式完成登录的案例:

步骤一:创建一个web项目,引入相应的jar包.

* mysql的驱动.

* jstl的包.

* beanutils的包.

步骤二:设计登录页面:

<h1>登录页面</h1>

<form action="" method="post">

<table border="1"width="400">

     <tr>

         <td>用户名</td>

         <td><input type="text"name="username"/></td>

     </tr>

     <tr>

         <td>密码</td>

         <td><inputtype="password" name="password"/></td>

     </tr>

     <tr>

         <tdcolspan="2"><input type="submit" value="登录"/></td>

     </tr>

</table>

</form>

步骤三:创建包结构:

* cn.itcast.web.servlet

* LoginServlet

* cn.itcast.service

* UserService

* cn.itcast.dao

* UserDao

* UserDaoImpl

* cn.itcast.domain

* User

* cn.itcast.utils

* JDBCUtils

步骤四:编写LoginServlet:

* 接收参数

* 封装数据

* 调用业务层类

* 页面跳转.

步骤五:编写UserService:

* 调用DAO.

 

步骤六:编写UserDao.

* 使用JDBC的操作完成对数据库查询.

 

步骤七:设计登录成功页面:

1.1.9     SQL注入的漏洞:

SQL注入的漏洞在早期互联网中是普遍存在.

已知用户名的情况下.对这个用户名的用户进行攻击!!!

* 1.攻击方式一:

在用户名地方输入:aaa' or '1=1

密码随意.

* 2.攻击方式二:

在用户名地方输入:aaa' -- 

密码随意.

 

产生原因:因为在用户名地方输入SQL的关键字.(SQL注入)

* DAO中SQL语句:

* select * from user where username = '' andpassword = '';

产生原因一:

* select * from user where username = 'aaa' or '1=1' and password = 'xxxx';

产生原因二:

* select * from user where username = 'aaa' -- 'and password = 'xxxx';

 

解决SQL注入的漏洞:

* 1.使用JS在文本框进行校验.校验不可以输入 -,or , ' 特殊的字符都不可以输入.

不可行:JS的校验只是为了提升用户的体验.不能真正进行校验.(JS的代码可以被绕行.

在地址上上直接输入访问路径.loginServlet?username=aaa'or '1=1&password=xxxxxx

 

* 2.SQL注入漏洞真正的解决方案:PreparedStatement.对SQL进行预编译.参数的地方都可以使用 ?作为占位符.

* select * from user where username = ? andpassword = ?;

再次输入 aaa' or '1=1 拿到参数之后. or 一些特殊的字符不当成SQL的关键字。只是当成普通的字符串进行解析.

提前进行编译.编译后的SQL的格式就已经固定了.

使用PreparedStatement改写了登录案例解决了SQL注入的漏洞!!!

1.1.10JDBC完成大文件的读写:(了解)

MYSQL数据库提供了两个数据类型:BLOB,TEXT用于存放文件.将文件存入到数据库.(数据库中存放的是上传文件路径.)

* Oracle:BLOB,CLOB.

文本文件的读写:

步骤一:创建一个表:

create table mytext(

id int primary key auto_increment,

data longtext

);

 

步骤二:读写文本文件:

@Test

/**

 * 将dulala.txt存入到数据库中.

 */

public void demo1(){

     Connection conn = null;

     PreparedStatement stmt =null;

     try{

         // 获得连接:

         conn =JDBCUtils.getConnection();

         // 编写SQL:

         String sql ="insert into mytext values (null,?)";

         // 预编译SQL:

         stmt =conn.prepareStatement(sql);

         // 设置参数:

         File file = newFile("src/dulala.txt");

         Reader reader = newFileReader(file);

         stmt.setCharacterStream(1,reader, (int)file.length());

         // 执行SQL;

         stmt.executeUpdate();

     }catch(Exception e){

         e.printStackTrace();

     }finally{

         JDBCUtils.release(stmt,conn);

     }

}

 

@Test

/**

 * 将数据库中存放的dulala.txt获得到.

 */

public void demo2(){

     Connection conn = null;

     PreparedStatement stmt =null;

     ResultSet rs = null;

     try{

         conn =JDBCUtils.getConnection();

         // 编写SQL:

         String sql ="select * from mytext where id = ?";

         // 预编译SQL:

         stmt =conn.prepareStatement(sql);

         // 设置参数:

         stmt.setInt(1, 1);

         // 执行SQL:

         rs = stmt.executeQuery();

         // 获得结果集的数据

         if(rs.next()){

             Reader reader =rs.getCharacterStream("data");

             Writer writer =new FileWriter("src/dulala_bak.txt");

             // 两个流对接:

             int len = 0;

             while((len =reader.read())!=-1){

                 writer.write(len);

             }

             reader.close();

             writer.close();

         }

     }catch(Exception e){

         e.printStackTrace();

     }finally{

         JDBCUtils.release(rs,stmt, conn);

     }

}

步骤三:修改Mysql的包大小.

* 在mysql的配置文件中:

[mysqld]下面添加:

max_allowed_packet=64M

二进制文件的读写:

步骤一:创建表

create table myblob(

id int primary key auto_increment,

data longblob

);

步骤二:读写大二级制文件:

@Test

/**

 * 将love china.mp3文件存入到数据库.

 */

public void demo1(){

     Connection conn = null;

     PreparedStatement stmt =null;

     try{

         // 获得连接:

         conn =JDBCUtils.getConnection();

         // 编写SQL语句:

         String sql ="insert into myblob values (null,?)";

         // 预编译SQL:

         stmt =conn.prepareStatement(sql);

         // 设置参数:

         File file = newFile("src/love china.mp3");

         InputStream is = newFileInputStream(file);

         stmt.setBinaryStream(1,is, (int)file.length());

         // 执行SQL;

         stmt.executeUpdate();

     }catch (Exception e) {

         e.printStackTrace();

     }finally{

         JDBCUtils.release(stmt,conn);

     }

}

 

@Test

/**

 * 将love china.mp3从数据库中读出来

 */

public void demo2(){

     Connection conn = null;

     PreparedStatement stmt =null;

     ResultSet rs = null;

     try{

         // 获得连接:

         conn =JDBCUtils.getConnection();

         // 编写SQL:

         String sql ="select * from myblob where id = ?";

         // 预编译SQL:

         stmt =conn.prepareStatement(sql);

         // 设置参数:

         stmt.setInt(1, 1);

         // 执行SQL:

         rs =stmt.executeQuery();

         // 获得结果集数据:

         if(rs.next()){

             InputStream is =rs.getBinaryStream("data");

             OutputStream os =new FileOutputStream("src/love china_bak.mp3");

             int len = 0;

             byte[] b = newbyte[1024];

            while((len = is.read(b))!=-1){

                 os.write(b, 0,len);

             }

             is.close();

             os.close();

         }

     }catch (Exception e) {

         e.printStackTrace();

     }finally{

         JDBCUtils.release(rs,stmt, conn);

     }

}

 

TEXT:

* TINYTEXT(255),TEXT(64K),MEDIUMTEXT(16M),LONGTEXT(4G)

BLOB:

* TINYBLOB(255),BLOB(64K),MEDIUMBLOB(16M),LONGBLOB(4G)

1.1.11JDBC批处理:

批处理:一批SQL一起执行.

* 企业中使用批处理进行批量的插入,修改的操作.

批处理的案例:

* 写多条SQL一起执行.

 

使用批处理批量向数据库插入10000条记录.

* MYSQL插入10000条记录 大概花费3-4分钟.

* 使用?rewriteBatchedStatements=true参数提升批处理运行的效率.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值