IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> [数据库]JDBC -> 正文阅读

[大数据][数据库]JDBC

什么是JDBC?

JDBC(Java Database Connectivity)是一个**独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口**(一组API),定义了用来访问数据库的标准Java类库,(**java.sql,javax.sql**)使用这些类库可以以一种**标准**的方法、方便地访问数据库资源。

如何使用JDBC?

大致分为六大步,分别是:

①加载驱动

②和数据库建立链接

③通过连接创建一个SQL命令发送器Statement(更好用的避免SQL注入的现在使用prepareStatement

④使用SQL命令发送器向数据库发送SQL命令。

⑤处理结果

⑥关闭资源

接下来根据这六步分别作出阐述和拓展

一、加载驱动

原始的比较机械的写法如下:

	@Test
    public void testConnection1() {
        try {
            //1.提供java.sql.Driver接口实现类的对象
            Driver driver = null;
            driver = new com.mysql.jdbc.Driver();

            //2.提供url,指明具体操作的数据
            String url = "jdbc:mysql://localhost:3306/test";

            //3.提供Properties的对象,指明用户名和密码
            Properties info = new Properties();
            info.setProperty("user", "root");
            info.setProperty("password", "abc123");

            //4.调用driver的connect(),获取连接
            Connection conn = driver.connect(url, info);
            System.out.println(conn);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

但现在一般使用将数据库需要的基本信息声明在配置文件中通过读取配置文件的方式获取连接。

首先是手动创建Properties文件

文件内容下;

#配置信息
user=root
password=你的密码
url=jdbc:mysql://localhost:3306/数据库名称?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true
driverClass=com.mysql.jdbc.Driver

二、连接数据库

然后是加载文件内容完成连接驱动:

/**
     * 使用德鲁伊数据库连接驱动
     */
    private static  DataSource ds;
    static {
        try {
            Properties pro = new Properties();
            pro.load(TestDruid.class.getClassLoader().getResourceAsStream("druid.properties"));
            ds = DruidDataSourceFactory.createDataSource(pro);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    public static Connection getConn1() throws SQLException {

        Connection conn = ds.getConnection();
        return conn;
    }
    //获取数据库连接

注:将创建对象的语句封装成一个静态代码块是一种节约资源的做法,如果写在方法内会多次创建浪费资源。

三、通过连接创建一个SQL命令发送器Statement(更好用的避免SQL注入的现在使用prepareStatement

通用的增删改和查询方法为例:

 /**
     * 通用增删改
     * @param sql
     * @param args
     * @throws SQLException
     * @throws ClassNotFoundException
     */
    public static void update(String sql, Object... args) {
        Connection conn = null;
        PreparedStatement pre = null;
        try {
            conn = JDBCUtils.getConn();
            pre = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                pre.setObject(i + 1, args[i]);
            }
            pre.execute();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.closeResource(conn, pre);

        }


    }

pre.excute;表示执行,但查询的执行语句和增删改有所不同:

  /**
     * 查询
     * @param sql
     * @param args
     * @throws SQLException
     * @throws ClassNotFoundException
     */
    public static List<SelectTools> select1(String sql, Object... args) {
        Connection conn = null;
        PreparedStatement pre = null;
        ResultSet resultSet=null;
        try {
            conn = JDBCUtils.getConn1();
            pre = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++){
                pre.setObject(i +1,args[i]);
            }//当存在可变参数时,args相当于一个数组,
            // 底层系统会先判断它的长度然后创建一个同等长度的数组,之后获取参数就遍历一下数组即可。

            resultSet =pre.executeQuery();

            int columnCount=rsmd.getColumnCount();
            List<SelectTools> list = new ArrayList<>();
            while (resultSet.next()){

                SelectTools se=new SelectTools();
                for (int i = 0; i <columnCount; i++) {
                    Object columnValue= resultSet.getObject(i+1);
                    String columnName=rsmd.getColumnLabel(i+1);
                    Field file= SelectTools.class.getDeclaredField(columnName);
                    file.setAccessible(true);
                    file.set(se,columnValue);
                }
                list.add(se);

            }
            return list;
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResource1(conn,pre,resultSet);

        }
        return null;


    }

执行块与增删改有区别:封装为结果集

?resultSet =pre.executeQuery();

处理结果集

if(resultSet.next()){

//判断结果集的下一条是否有数据,如果有就返回true,并且指针下移,反返回false,指针不下移。

//获取各个字段值

int id=resultSet.getInt(1);

String name=resultSet.getString(2);

..........以此类推

}

四、使用SQL命令发送器向数据库发送SQL命令。

一般将SQL写在执行类(测试类):

事先准备:提前写好一个声明字段属性的工具类,属性和增删改查所要用的字段或者别名保持一致。

public class SelectTools {
 private String name;
 private String com;
 private int count;

    @Override
    public String toString() {
        return "SelectTools{" +
                "name='" + name + '\'' +
                ", com='" + com + '\'' +
                ", count=" + count +
                '}';
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCom() {
        return com;
    }

    public void setCom(String com) {
        this.com = com;
    }

    public SelectTools() {
    }


}

然后在执行类(测试类)里面定义和写入SQL语句:

public class QueryRunnerTest {
    @Test
    public void QueryRunnerTest() throws SQLException {
        Connection conn= null;
        try {
            conn = JDBCUtils.getConn1();
            QueryRunner runner=new QueryRunner();
            String sql="SELECT p.p_name `name`,COUNT(*) `count`\n" +
                    "FROM sales s,deal d,production p\n" +
                    "WHERE s.s_no=d.s_no AND p.p_no=d.p_no\n" +
                    "GROUP BY d.p_no";
            MapListHandler handler=new MapListHandler();
            List<Map<String,Object>> wan = runner.query(conn,sql,handler);
            wan.forEach(System.out::println);}
 }
}

由于没有关闭资源的操作,执行并不是很快。

上文查询是通过德鲁伊数据库连接驱动的查询并使用了其中的Druid的jar包中的封装的查询方法。

五、处理结果

ResultSet类的作用

ResultSet(结果集)是数据库结果集的数据表,通常通过执行查询数据库的语句生成

一个ResultSet对象对应着一个由查询语句返回的一个表这个表中包含所有的查询结果。可以说结果集是一个存储查询结果的对象,但是结果集并不仅仅具有存储的功能,他同时还具有操纵数据的功,可能完成对数据的更新等。

实际上,我们就可以将一个ResultSet对象看成一个表。对ResultSet对象的处理必须逐行进行,而对每一行中的各个列,可以按任何顺序进行处理。

  • 注意:Java与数据库交互涉及到的相关Java API中的索引都从1开始。

//处理结果集

 try {
            conn = JDBCUtils.getConn1();
            pre = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++){
                pre.setObject(i +1,args[i]);
            }//当存在可变参数时,args相当于一个数组,
            // 底层系统会先判断它的长度然后创建一个同等长度的数组,之后获取参数就遍历一下数组即可。

            resultSet =pre.executeQuery();

            int columnCount=rsmd.getColumnCount();
            List<SelectTools> list = new ArrayList<>();
            while (resultSet.next()){

                SelectTools se=new SelectTools();
                for (int i = 0; i <columnCount; i++) {
                    Object columnValue= resultSet.getObject(i+1);
                    String columnName=rsmd.getColumnLabel(i+1);
                    Field file= SelectTools.class.getDeclaredField(columnName);
                    file.setAccessible(true);
                    file.set(se,columnValue);
                }
                list.add(se);

            }
            return list;
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResource1(conn,pre,resultSet);

        }
        return null;

六、关闭资源

关闭资源基本是就是做一个if非空判断,然后根据判断结果关闭资源。

  /**针对查询的
     * 关闭资源(包含结果集)
     * @param conn
     * @param pre
     */
    public static void closeResource1(Connection conn, PreparedStatement pre, ResultSet resultSet){
//最简单的写法直接调用DbUtils里面的方法,其底层和正常写法一致:
        DbUtils.closeQuietly(conn);
        DbUtils.closeQuietly(pre);
        DbUtils.closeQuietly(resultSet);
//正常写法:
//        try{
//            if (pre != null) {
//                pre.close();
//            }
//        } catch (SQLException e) {
//            e.printStackTrace();
//        }
//        try {
//            if (pre != null) {
//                conn.close();
//            }
//        } catch (SQLException e) {
//            e.printStackTrace();
//        }
//        try {
//            if (resultSet != null) {
//                conn.close();
//            }
//        } catch (SQLException e) {
//            e.printStackTrace();
//        }

    }

针对Blob类型字段的操作:

BLob字段类型
类型字节
TinyBlob255B
Blob65Kb
LongBLOb4G
MediumBlob16M

注:如果指定了Blob类型以后还报错,找my.ini文件加上

max_allowed_packed=16M?? 然后重启mysql服务。

// 向数据表中插入大数据类型
//获取连接
Connection conn = JDBCUtils.getConnection();
		
String sql = "insert into customers(name,email,birth,photo)values(?,?,?,?)";
PreparedStatement ps = conn.prepareStatement(sql);

// 填充占位符
ps.setString(1, "徐海强");
ps.setString(2, "xhq@126.com");
ps.setDate(3, new Date(new java.util.Date().getTime()));
// 操作Blob类型的变量
FileInputStream fis = new FileInputStream("xhq.png");
ps.setBlob(4, fis);
//执行
ps.execute();
		
fis.close();
JDBCUtils.closeResource(conn, ps);
//从数据表中读取大数据类型
//……
String sql = "SELECT id, name, email, birth, photo FROM customer WHERE id = ?";
conn = getConnection();
ps = conn.prepareStatement(sql);
ps.setInt(1, 8);
rs = ps.executeQuery();
if(rs.next()){
	Integer id = rs.getInt(1);
    String name = rs.getString(2);
	String email = rs.getString(3);
    Date birth = rs.getDate(4);
	Customer cust = new Customer(id, name, email, birth);
    System.out.println(cust); 
    //读取Blob类型的字段
	Blob photo = rs.getBlob(5);
	InputStream is = photo.getBinaryStream();
	OutputStream os = new FileOutputStream("c.jpg");
	byte [] buffer = new byte[1024];
	int len = 0;
	while((len = is.read(buffer)) != -1){
		os.write(buffer, 0, len);
	}
    JDBCUtils.closeResource(conn, ps, rs);
		
	if(is != null){
		is.close();
	}
		
	if(os !=  null){
		os.close();
	}
    
}

批量操作,根据事务的特性可以批量操作:

举例:向数据表中插入20000条数据

/*
* 
* 使用Connection 的 setAutoCommit(false)  /  commit()
*/
@Test
public void testInsert2() throws Exception{
	long start = System.currentTimeMillis();
		
	Connection conn = JDBCUtils.getConnection();
		
	//1.设置为不自动提交数据
	conn.setAutoCommit(false);
		
	String sql = "insert into goods(name)values(?)";
	PreparedStatement ps = conn.prepareStatement(sql);
		
	for(int i = 1;i <= 1000000;i++){
		ps.setString(1, "name_" + i);
			
		//1.“攒”sql
		ps.addBatch();
			
		if(i % 500 == 0){
			//2.执行
			ps.executeBatch();
			//3.清空
			ps.clearBatch();
		}
	}
		
	//2.提交数据
	conn.commit();
		
	long end = System.currentTimeMillis();
	System.out.println("花费的时间为:" + (end - start));//1000000条:4978 
		
	JDBCUtils.closeResource(conn, ps);
}

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-07-03 10:53:18  更:2022-07-03 10:57:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 20:02:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码