Scala应用 —— JDBC的创建

ops/2024/9/23 11:13:26/

在这里插入图片描述
在这里插入图片描述

文章目录

  • Scala应用 —— JDBC的创建
      • 前言
      • 一、JDBC的创建过程
          • 1.初始化连接
            • 1.1 配置驱动
            • 1.2 创建连接对象
          • 2. 初始化执行器
            • 2.1 创建执行器对象
            • 2.2 初始化执行器参数
          • 3. 执行操作并返回结果
      • 二、Scala JDBC的基本设计思路
          • 1. 操作步骤设计
          • 2. 解决结果差异化
          • 3.实现jdbc方法并输出结果
      • 三、代码汇总与结果
          • 1. 代码
          • 2.结果

JDBC_3">Scala应用 —— JDBC的创建

前言

该文章旨在通过Scala语言实现JDBC的创建,以熟悉Scala语言的使用。

JDBC_7">一、JDBC的创建过程

1.初始化连接
1.1 配置驱动

在pom.xml中打入以下依赖,向项目中打入MySQL JDBC驱动

<!-- MySQL 驱动 -->
<dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>8.0.33</version>
</dependency>

该语句用于加载MySQL JDBC驱动。

Class.forName("com.mysql.cj.jdbc.Driver")
1.2 创建连接对象

参数:url,username,password

2. 初始化执行器

执行器的创建需要依赖连接对象,因此先初始化连接再初始化执行器。

2.1 创建执行器对象

参数:sql,parameters

2.2 初始化执行器参数
3. 执行操作并返回结果
  • DML:影响数据库的表行数
  • DQL:List
  • Exception:异常

JDBC_55">二、Scala JDBC的基本设计思路

JDBC的创建实际上就是包含了两个操作步骤和一个多返回类型设计的小型化任务。

1. 操作步骤设计
scala">def jdbc(url:String,username:String,password:String)(sql:String,params:Seq[Any]=null):Unit{}
  • 多操作过程可以写成柯里化的形式,不仅实现了参数分组,同时还隐含了一种参数间的依赖关系

  • params不一定会有,并且可能同时包含多种不同的数据类型。

    因此可以通过可变参数T*或者序列Seq[T]的方式进行表示。

    同时,默认情况下不传参,因此指定一个默认值为null

    • Any*
    • Seq[Any]
2. 解决结果差异化

结果类型包括:

  • DML:影响数据库的表行数
  • DQL:List
  • Exception:异常

JDBC的结果类型包含了两种正常类型和一种异常类型,自带的OptionEitherTry都无法满足这种需求,我们的解决方式如下:

  1. 首先定义了一个名为ResultType的枚举类型,它包含三个值:EX,DQLDML
  2. 定义了一个抽象类Three,它包含了一个类型为ResultType.Value的构造参数,这个参数用来表示具体的结果类型。此处选择抽象类是因为需要传递一个构造参数,这种设计允许在继承Three的子类中具体化不同类型的结果处理(差异化处理)。
  3. 三个样例类(Ex,DML,和 DQL)继承自抽象类 Three,每个样例类都对应一个 ResultType 的值,并封装了与其类型相关的数据。
scala">object ResultType extends Enumeration{val EX,DQL,DML = Value
}abstract class Three(val rst:ResultType.Value)case class Ex(throwable: Throwable) extends Three(ResultType.EX){def ex = throwable
}case class DML(affectedRows:Int) extends Three(ResultType.DML){def updated = affectedRows
}case class DQL(set: ResultSet) extends Three(ResultType.DQL){/*** 为什么要将(f:ResultSet=>T)独立为一个方法的参数?* 减少不必要的类型约束,不需要每次创建DQL对象都需要指定泛型。* */def generate[T](f:ResultSet=>T)(implicit ct:ClassTag[T])={val buffer:ArrayBuffer[T] = ArrayBuffer()// 遍历结果集(包含由一次查询返回的所有行),用f将结果集的每一行转化为一个实体while (set.next()) {buffer.append(f(set))}buffer.toArray}
}
3.实现jdbc方法并输出结果
  • 基类通过asInstanceOf[T]的方法实现向具体子类的转化
  • id = rst.getInt(1)这类语句是通过字段序号代替了字段名称
    在这里插入图片描述
scala">def jdbc(url: String, username: String, password: String)(sql: String, params: Seq[Any] = null): Three = {def conn(): Connection = {// 1.1 装载驱动Class.forName("com.mysql.cj.jdbc.Driver")// 1.2 创建连接对象val conn: Connection = DriverManager.getConnection(url, username, password)conn}def pst(conn: Connection): PreparedStatement = {// 2.1 创建执行对象val pst: PreparedStatement = conn.prepareStatement(sql)// 2.2 设置sql配置为(序号,参数)的格式if (null != params && params.nonEmpty) {params.zipWithIndex.foreach {// 设置执行对象对应的SQL语句`?`对应的占位符。case (param, index) => pst.setObject(index + 1, param)}}pst}try {val connect: Connection = connval statement: PreparedStatement = pst(connect)// 过程级增删改查(数据记录):INSERT DELETE UPDATE SELECT// 对象级增删改查(对象——表、视图、索引):CREATE DROP ALTER SHOWsql match {case sql if sql.matches("SELECT|select") => DQL(statement.executeQuery())case sql if sql.matches("INSERT|insert|DELETE|delete|UPDATE|update") => DML(statement.executeUpdate())// 处理SQL语句异常case _ => Ex(new SQLException(s"illegal sql command:$sql"))}} catch {// 其他异常case e: Exception => Ex(e)}
}def main(args: Array[String]): Unit = {val dql: DQL = jdbc(url = "jdbc:mysql://single01:3306/test_db_for_bigdata",username = "root",password = "123456")(sql = "SELECT * FROM test_table1_for_hbase_import LIMIT 20").asInstanceOf[DQL]// 将结果集对应的字段设置为样例类,自动生成getter方法case class Test(id: Int, name: String, age: Int, gender: String, phone: String)// 将结果集的每一行转化为一个Test对象val tests: Array[Test] = dql.generate[Test](rst => Test(id = rst.getInt(1),name = rst.getString(2),age = rst.getInt(3),gender = rst.getString(4),phone = rst.getString(5)))tests.foreach(println)
}

三、代码汇总与结果

1. 代码
scala">package recoveryimport java.sql.{Connection, DriverManager, PreparedStatement, ResultSet, SQLException}
import scala.collection.mutable.ArrayBuffer
import scala.reflect.ClassTagobject JDBCTest2 {object ResultType extends Enumeration{val EX,DQL,DML = Value}abstract class Three(val rst:ResultType.Value)case class Ex(throwable: Throwable) extends Three(ResultType.EX){def ex = throwable}case class DML(affectedRows:Int) extends Three(ResultType.DML){def updated = affectedRows}case class DQL(set: ResultSet) extends Three(ResultType.DQL){/*** 为什么要将(f:ResultSet=>T)独立为一个方法的参数?* 减少不必要的类型约束,不需要每次创建DQL对象都需要指定泛型。* */def generate[T](f:ResultSet=>T)(implicit ct:ClassTag[T])={val buffer:ArrayBuffer[T] = ArrayBuffer()// 遍历结果集(包含由一次查询返回的所有行),用f将结果集的每一行转化为一个实体while (set.next()) {buffer.append(f(set))}buffer.toArray}}def jdbc(url: String, username: String, password: String)(sql: String, params: Seq[Any] = null): Three = {def conn(): Connection = {// 1.1 装载驱动Class.forName("com.mysql.cj.jdbc.Driver")// 1.2 创建连接对象val conn: Connection = DriverManager.getConnection(url, username, password)conn}def pst(conn: Connection): PreparedStatement = {val pst: PreparedStatement = conn.prepareStatement(sql)if (null != params && params.nonEmpty) {params.zipWithIndex.foreach {// 设置执行对象对应的SQL语句`?`对应的占位符。case (param, index) => pst.setObject(index + 1, param)}}pst}try {val connect: Connection = connval statement: PreparedStatement = pst(connect)// 过程级增删改查(数据记录):INSERT DELETE UPDATE SELECT// 对象级增删改查(对象——表、视图、索引):CREATE DROP ALTER SHOWsql match {case sql if sql.matches("SELECT|select") => DQL(statement.executeQuery())case sql if sql.matches("INSERT|insert|DELETE|delete|UPDATE|update") => DML(statement.executeUpdate())case _ => Ex(new SQLException(s"illegal sql command:$sql"))}} catch {case e: Exception => Ex(e)}}def main(args: Array[String]): Unit = {val result = jdbc(url = "jdbc:mysql://single01:3306/test_db_for_bigdata",username = "root",password = "123456")(sql = "SELECT * FROM test_table1_for_hbase_import LIMIT 20;")result match {case dql: DQL =>case class Test(id: Int, name: String, age: Int, gender: String, phone: String)val tests: Array[Test] = dql.generate[Test](rst => Test(id = rst.getInt(1),name = rst.getString(2),age = rst.getInt(3),gender = rst.getString(4),phone = rst.getString(5)))tests.foreach(println)case ex: Ex =>println("Error occurred: " + ex.ex.getMessage)}}
2.结果

在这里插入图片描述

在这里插入图片描述


http://www.ppmy.cn/ops/29654.html

相关文章

机器学习-什么是 k-means?

1、什么是 k-means&#xff1f; k-means是一种无监督的分类学习算法。它的基本原理是以距离作为相似度的评价指标&#xff0c;用样本点到类别中心的误差平方和作为聚类好坏的评价指标&#xff0c;通过迭代的方法使总体分类的误差评分和函数达到最小的聚类方法。 2、 k-means聚…

C++ STL

1. STL基本概念 1.1 STL六大组件 STL六大组件&#xff1a;容器、算法、迭代器、仿函数、适配器、空间适配器 2.4 STL中容器、算法、迭代器 2.5 容器算法 迭代器 2.5.1 vector存放内置数据类型 容器&#xff1a;vector 算法&#xff1a;for_each 迭代器&#xff1a;vector::it…

【抽代复习笔记】17-群(十一):置换的练习题(1)

练习1&#xff1a;计算&#xff1a; 解&#xff1a; 解析&#xff1a;①左边的置换是1保持不变&#xff0c;2变成3&#xff0c;3变成4&#xff0c;4变成5&#xff0c;5变成2&#xff0c;因此可以简写为(2345)&#xff1b;右边的置换是2和5保持不变&#xff0c;1变成3&#xff…

Java | Leetcode Java题解之第64题最小路径和

题目&#xff1a; 题解&#xff1a; class Solution {public int minPathSum(int[][] grid) {if (grid null || grid.length 0 || grid[0].length 0) {return 0;}int rows grid.length, columns grid[0].length;int[][] dp new int[rows][columns];dp[0][0] grid[0][0]…

大数据之数据仓库技术:ETL工具和Kettle简介

大数据之数据仓库技术&#xff1a;ETL工具和Kettle简介 ETL简介ETL工具和KettleKettle家族 Kettle资源KettlePack 任务调度工具 ETL简介 ETL(Extract-Transform-Load): 在大数据技术领域内&#xff0c;用来描述将数据从 来源端 经过 抽取(extract), 转换(transform), 加载(loa…

双非二本找工作前的准备day18

学习目标&#xff1a; 每天复习代码随想录上的题目1-2道算法&#xff08;时间充足可以继续&#xff09; 今日碎碎念&#xff1a; 1&#xff09;5/1假期啦&#xff0c;明天去天坛看看&#xff0c;但是算法不能漏&#xff0c; 2&#xff09;出租屋里不知道干啥&#xff0c;看看…

C++基础—模版

C模板是C语言中实现泛型编程的核心机制&#xff0c;它允许程序员定义通用的代码框架&#xff0c;这些框架在编译时可以根据提供的具体类型参数生成相应的特定类型实例。 泛型编程的特点代码复用和安全性! 模板主要分为两大类&#xff1a;函数模板和类模板。 函数模板 基本语…

Sqlmap使用

sqlmap -u "http://example.com/index.php?id1" --tables sqlmap查看表名 1、检测「注入点」 sqlmap -u http://xx/?id1 2、查看所有「数据库」 sqlmap -u http://xx/?id1 --dbs 3、查看当前使用的数据库 sqlmap -u http://xx/?id1 --current-db 4、查看「数…