JDBC学习之一

JDBC学习1

JDBC简介

JDBC:Java DataBase Connectivity,是SUN推出的操作数据库的规范。
JDBC和数据库驱动:规范和实现的关系。
JDBC:JDK中。java.sql.;javax.sql.;
驱动:去数据库厂商的网站下载

JDBC开发步骤

  1. 搭建开发环境:把数据库驱动的jar包加入到构建路径中。
  2. 注册驱动
  3. 获取与数据库的链接
  4. 创建代表SQL语句的对象
  5. 执行SQL语句(如果是查询语句:返回结果集。)
  6. 遍历结果集里的内容
  7. 释放资源
    代码:
package com.jyh.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import com.jyh.domain.User;

public class JDBCConnect {

    public static void main(String[] args) throws Exception{

        //1.注册驱动
        //DriverManager.registerDriver(new Driver());

        //2.获取链接
        //Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/database1", "root", "ying1995520***");

        //3.创建代表sql语句的对象
        Statement st = conn.createStatement();

        //4.执行SQL语句(如果是查询语句则返回结果集)
        ResultSet rs = st.executeQuery("select * from user");

        //5.遍历返回的结果集里面的内容
        List<User> list = new ArrayList<>();
        while(rs.next()){
            User user = new User();
            user.setId(rs.getString("id"));
            user.setName(rs.getString("name"));
            user.setPassword(rs.getString("password"));
            user.setEmail(rs.getString("email"));
            user.setBirthday(rs.getDate("birthday"));
            list.add(user);
        }
        System.out.println(list.size());

        //6.释放资源
        rs.close();
        st.close();
        conn.close();
    }
}

JDBC规范中常用的接口和类

DriverManager

作用:

1. 注册驱动
1. 方式一:DriverManager.registerDriver(new com.mysql.jdbc.Driver());
缺点:
1. 严重依赖具体的数据库驱动
2. 导致数据驱动注册2遍
2. 方式二:(推荐)

2. 获取与数据库的链接
1. 方式一:
Connection conn = DriverManager.getConnection(“jdbc:mysql://localhost:3306/day15”,
“root”, “sorry”);
String url:JDBC与数据库厂商的协议。具体参考数据库的文档。
Oracle:jdbc:oracle:thin:@localhost:1521:orcl 瘦客户端链接方式
jdbc:oracle:client:@localhost:1521:orcl 客户端链接方式,高效
2. 方式二:
Connection conn = DriverManager.getConnection(“jdbc:mysql:///day15?user=root&password=sorry”);

Connection

作用:所有与数据库的交互都是基于链接的。

Statement

作用:代表SQL语句对象

常用方法:
- ResultSet executeQuery(String sql):执行查询,返回结果集。
- int executeUpdate(String sql):执行DML语句。返回的是SQL语句影响到的记录条数。
- boolean execute(String sql):执行任何的SQL语句。返回值不代表成功与否。如果执行的语句有结果集,返回true,否则返回false。

ResultSet

作用:封装了结果集
rs.getString("id") 根据列名获取值
rs.getString(1) 根据列好获取值,从1开始

数据库类型和Java类型的对应关系:

SQL类型JDBC对应方法返回类型
BIT(1) bit(n)getBolean() getBytes()Boolean byte[]
TINYINTgetByte()Byte
SMALLINTgetShort()Short
IntgetInt()Int
BIGINTgetLong()Long
CHAR,VARCHAR,LONGVARCHARgetString()String
Text(clob) blobgetClob() getBlob()Clob Blob
DATEgetDate()java.sql.Date
TIMEgetTime()java.sql.Time
TIMESTAMPgetTimestamp()java.sql.Timestamp

常用的方法:
boolean next():向下移动。返回有没有记录
boolean provious():向上移动。返回有没有记录
boolean absolute(int row):定位。返回有没有记录。看第2条,写2.
void beforeFirst():移动到第一条记录的前面。默认位置
void afterLast():移动到最后一条记录的后面。

抽取JDBC的工具类

package com.jyh.jdbc;

import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;



public class JdbcUtil {

    private static String driverClass;
    private static String url;
    private static String user;
    private static String password;

    static{
        try {
            //获取配置文件路径
            String path = JdbcUtil.class.getClassLoader().getResource("jdbcConfig.properties").getPath();
            //读取配置文件
            InputStream is = new FileInputStream(path);
            //将配置文件中的内容加载进Properties中
            Properties ps = new Properties();
            ps.load(is);
            is.close();
            //获取配置属性值
            driverClass = ps.getProperty("driverClass");
            url = ps.getProperty("url");
            user = ps.getProperty("user");
            password = ps.getProperty("password");
            //注册数据库驱动
            Class.forName(driverClass);
        } catch (Exception e) {
            throw new ExceptionInInitializerError();
        }
    }

    //获取链接
    public static Connection getConnection() throws Exception{
        Connection conn = DriverManager.getConnection(url, user, password);
        return conn;
    }

    //关闭链接
    public static void release(ResultSet rs,Statement st,Connection conn){
        if(st != null){
            try {
                st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            st = null;
        }
        if(rs != null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            rs = null;
        }
        if(conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            conn = null;
        }
    }
}

PreparedStatement接口

原则:能用PreparedStatement就不要使用Statement
优点:
- 参数使用占位符(?)替代
- 预编SQL语句,执行效率高
- 不存在SQL注入问题

批处理

//如果批处理执行的语句不相同,最好使用Statement
    public void test1(){
        Connection conn = null;
        Statement stmt =  null;
        try{
            conn = JdbcUtil.getConnection();
            stmt = conn.createStatement();//内部有一个List,就是sql语句的缓存

            String sql1 = "insert into t1 (id,name) values(1,'aa1')";
            String sql2 = "insert into t1 (id,name) values(2,'aa2')";
            String sql3 = "delete from t1 where id=1";

            stmt.addBatch(sql1);
            stmt.addBatch(sql2);
            stmt.addBatch(sql3);

            int [] ii = stmt.executeBatch();//批处理.每条语句影响的行数

            for(int i:ii)
                System.out.println(i);
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JdbcUtil.release(null, stmt, conn);
        }
    }

//很多时候:语句相同,只是参数不同
    //PreparedStatement
    //插入10条记录
    @Test
    public void test2(){
        Connection conn = null;
        PreparedStatement stmt =  null;
        try{
            conn = JdbcUtil.getConnection();
            stmt = conn.prepareStatement("insert into t1 (id,name) values(?,?)");

            for(int i=0;i<10;i++){
                stmt.setInt(1, i+1);
                stmt.setString(2, "aa"+(i+1));
                stmt.addBatch();//向缓存中加的参数
            }

            int [] ii = stmt.executeBatch();//批处理.每条语句影响的行数

            for(int i:ii)
                System.out.println(i);
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JdbcUtil.release(null, stmt, conn);
        }
    }

LOB(CLOB、BLOB)的存取

  1. LOB:Large Object。
    CLOB:character Large Object。大文本。
    BLOB:Binary Large Object。图片、视频、声音等。
  2. MySQL支持的LOB的类型。可变长度类型。
    TINYBLOB, TINYTEXT 256B
    BLOB, TEXT 64K
    MEDIUMBLOB, MEDIUMTEXT 16M
    LONGBLOB, LONGTEXT 4G
package com.jyh.lob;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

import org.junit.Test;

import com.jyh.jdbc.JdbcUtil;

public class LobTest {

    /**
     * create table t1(
     *  id int primary key,
     *  content longtext
     * )
     * @throws Exception 
     */
    //数据库文本写入
    @Test
    public void testTextWrite() throws Exception{
        Connection conn = JdbcUtil.getConnection();
        PreparedStatement st = conn.prepareStatement("insert into t1(id,content) values(?,?)");
        st.setInt(1, 1);
        File file = new File("src/clob.txt");
        Reader reader = new FileReader(file);
        //setCharacterStream(int, Reader, long)MySQL没实现,因为MySQL最大存储小于long类型
        st.setCharacterStream(2, reader, (int)file.length());
        st.executeUpdate();
        JdbcUtil.release(null, st, conn);
    }

    //数据库文本读取
    @Test
    public void testTextRead() throws Exception{
        Connection conn = JdbcUtil.getConnection();
        PreparedStatement st = conn.prepareStatement("select content from t1 where id = ?");
        st.setInt(1, 1);
        ResultSet rs = st.executeQuery();
        if(rs.next()){
            Reader reader = rs.getCharacterStream("content");
            Writer wr = new FileWriter("d:/tt.txt");
            char[] c = new char[1024];
            int len = -1;
            while((len = reader.read(c)) != -1){
                wr.write(c, 0, len);
            }
            wr.flush();
            reader.close();
            wr.close();
        }
        JdbcUtil.release(rs, st, conn);
    }
    /**
     * create table t2(
     *  id int primary key,
     *  content longblob
     * )
     * @throws Exception 
     */
    //二进制数据写入(图片、音频、视频等)
    @Test
    public void testBinaryWrite() throws Exception{
        Connection conn = JdbcUtil.getConnection();
        PreparedStatement st = conn.prepareStatement("insert into t2(id,content) values(?,?)");
        st.setInt(1, 1);
        InputStream in = new FileInputStream("src/1044490.jpg");
        st.setBinaryStream(2, in , in.available());
        st.executeUpdate();
        JdbcUtil.release(null, st, conn);
    }

    //二进制数据读取(图片、音频、视频等)
    @Test
    public void testBinaryRead() throws Exception{
        Connection conn = JdbcUtil.getConnection();
        PreparedStatement st = conn.prepareStatement("select content from t2 where id = ?");
        st.setInt(1, 1);
        ResultSet rs = st.executeQuery();
        if(rs.next()){
            InputStream in = rs.getBinaryStream("content");
            OutputStream out = new FileOutputStream("d:/1.jpg");
            byte[] b = new byte[1024];
            int len = -1;
            while((len = in.read(b)) != -1){
                out.write(b, 0, len);
            }
            out.flush();
            in.close();
            out.close();
        }
        JdbcUtil.release(rs, st, conn);
    }
}

事务的入门

数据库的事务控制

start transaction:开启事务
rollback:回滚事务
commit:提交事务

JDBC控制事务

package com.jyh.transaction;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Savepoint;

import org.junit.Test;

import com.jyh.jdbc.JdbcUtil;


public class TransactionDemo {

    @SuppressWarnings("resource")
    @Test
    public void demo1(){
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;
        Savepoint sp = null;
        try{
            conn = JdbcUtil.getConnection();
            conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);//在事务之前设置事务的隔离级别
            conn.setAutoCommit(false);//事务起始点
            st = conn.prepareStatement("update account set salary=salary+100 where id = 1");
            st.executeUpdate();
            st = conn.prepareStatement("update account set salary=salary-100 where id = 2");
            st.executeUpdate();

            sp = conn.setSavepoint();//回滚点

            st = conn.prepareStatement("update account set salary=salary+100 where id = 1");
            st.executeUpdate();

            @SuppressWarnings("unused")
            int i = 1/0;

            st = conn.prepareStatement("update account set salary=salary-100 where id = 3");
            st.executeUpdate();
        }catch(Exception e){
            if(conn != null){
                try {
                    conn.rollback(sp);//回滚到回滚点
                } catch (SQLException e1) {
                    e1.printStackTrace();
                }
            }
        }finally{
            if(conn != null){
                try {
                    conn.commit();//提交事务
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            JdbcUtil.release(rs, st, conn);
        }
    }
}

事务的特性

事务的特性

  1. 原子性:指处于同一个事务中的多条语句是不可分割的,要么全部成功,要么全部失败。
  2. 一致性:事务必须使数据库从一个一致性状态变换到另外一个一致性状态,相当于守恒。比如,转账,转账前两个账户余额之和为2k,转账之后也应该是2K。
  3. 隔离性:指多线程环境下,一个线程中的事务不能被其他线程中的事务打扰
  4. 持久性:事务一旦提交,就应该被永久保存起来。

事务隔离性专题

如果不考虑事务的隔离性,会出现以下问题:
1. 脏读:指一个线程中的事务读取到了另外一个线程中未提交的数据。
2. 不可重复读:指一个线程中的事务读取到了另外一个线程中提交的update的数据。
3. 虚读:指一个线程中的事务读取到了另外一个线程中提交的insert的数据。

隔离级别:
1:READ UNCOMMITTED:脏读、不可重复读、虚读都有可能发生。
2:READ COMMITTED:防止脏读的发生,不可重复读、虚读都有可能发生。
4:REPEATABLE READ:防止脏读、不可重复读的发生,虚读有可能发生。
8:SERIALIZABLE:防止脏读、不可重复读、虚读的发生。
级别越高,数据越安全,但性能越低。

  1. 脏读:事务提交之前发生。
    a事务还没提交,b事务开始,然后获取的数据是a事务还没提交的数据。
    READ COMMITTED就是防止脏读发生
  2. 不可重复读:事务提交之后发生。
    a拿着工资卡去消费(a事务开启),系统读取到卡里确实有5000元,而此时他的老婆也正好在网上转账,把a工资卡的5000元转到另一账户(b事务开启),并在a之前提交了事务(b事务提交),当a扣款时,系统检查到a的工资卡已经没有钱,扣款失败,a十分纳闷,明明卡里有钱,为何……
    总结就是a事务开始—>b事务开始—>b事务结束—>a事务结束
    导致a得到的数据前后不一致
    REPEATABLE READ解决不可重复读,相当于在操作某条数据的时候就已经锁定了该条数据,使得别人无法修改。
  3. 虚读:事务提交之后发生。
    虚读其实跟不可重复读差不多,也是前后数据不一致,不过不是某一条,而是当前表格数据发生变化,也就是增加了一条数据。a事务开始读的时候是5条,然后b添加了一条就关闭了事务,a这时候还没关闭,再读取的时候就多了一条。
    SERIALIZABLE是最高级别,防止了脏读,不可重复读和虚读,在我理解就相当于锁定了整张表,在某一个事务操作该表的时候,其它任何事务都不能对该表进行操作。

MySQL控制事务的隔离级别:
查看当前事务的隔离级别:SELECT @@tx_isolation;
更改事务的隔离级别:(注意:一定要在开启事务之前设定)
SET transaction isolation level 四个级别之一(单词);

JDBC中如何控制事务的隔离级别:
前提:在开启事务之前设置隔离级别。
javaconn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);//在事务之前设置事务的隔离级别

事务的隔离级别表示

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值