Scala应用 —— JDBC的创建

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

文章目录

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

Scala应用 —— JDBC的创建

前言

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

一、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:异常

二、Scala JDBC的基本设计思路

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

1. 操作步骤设计
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 的值,并封装了与其类型相关的数据。
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)这类语句是通过字段序号代替了字段名称
    在这里插入图片描述
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. 代码
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.mzph.cn/bicheng/5949.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WPF之创建无外观控件

1&#xff0c;定义无外观控件。 定义默认样式&#xff0c;在其静态构造函数中调用DefaultStyleKeyProperty.OverrideMetadata()。 //设置默认样式DefaultStyleKeyProperty.OverrideMetadata(typeof(ColorPicker), new FrameworkPropertyMetadata(typeof(ColorPicker))); 在项目…

UE4_Niagara_两个模型之间的粒子幻化

学习笔记&#xff0c;仅供参考&#xff01; 操作步骤&#xff1a; 1、新建niagara system&#xff0c;添加空的发射器&#xff0c;渲染改为网格体渲染器&#xff0c;网格体为1M_Cube. 2、创建粒子材质重载。 3、渲染网格体的材质设置&#xff1a; 4、在发射器属性面板&#x…

基于MSOGI的交叉对消谐波信号提取网络MATLAB仿真

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 模型简介&#xff1a; 此模型利用二阶广义积分器&#xff08;SOGI&#xff09;对基波电流和相应次的谐波电流进行取 &#xff0c;具体是通过多个基于二阶广义积分器的正交信号发生器 &#xff08; S&#xf…

docker挂载数据卷-以nginx为例

目录 一、什么是数据卷 二、数据卷的作用 三、如何挂载数据卷 1、创建nginx容器挂载数据卷 2、查看数据卷 3、查看数据卷详情 4、尝试在宿主机修改数据卷 5、查看容器内对应的数据卷目录 6、 访问nginx查看效果 ​​​​​​​一、什么是数据卷 挂载数据卷本质上就是实…

【跟马少平老师学AI】-【神经网络是怎么实现的】(八)循环神经网络

一句话归纳&#xff1a; 1&#xff09;词向量与句子向量的循环神经网络&#xff1a; x(i)为词向量。h(i)为含前i个词信息的向量。h(t)为句向量。 2&#xff09;循环神经网络的局部。 每个子网络都是标准的全连接神经网络。 3&#xff09;对句向量增加全连接层和激活函数。 每个…

嵌入式开发三:STM32初体验

本节主要向大家介绍如何开发过程中的基本操作&#xff0c;如编译、串口下载、仿真器下载、仿真调试程序&#xff0c;体验一下 STM32 的开发流程&#xff0c;并介绍 MDK5 的一些使用技巧&#xff0c;通过本节的学习&#xff0c;将对 STM32 的开发流程和 MDK5 使用有个大概了解&a…

安装部署大语言模型 | 通义千问

下载安装 进入ollama的仓库下载 「 qwen 7b 」 libraryGet up and running with large language models.https://ollama.com/library查找阿里的 「 qwen 」 根据自己的电脑配置情况&#xff0c;选择合适的模型 总体来说&#xff0c;模型是越大&#xff0c;效果越好&#xff0c…

019、Python+fastapi,第一个Python项目走向第19步:windows 11 下的pycharm远程连接ubuntu 24.04 服务器

一、说明 欲善其事,必先利其器&#xff0c;先把环境整好&#xff0c;我开发的环境是ubuntu是没有gui的服务器版本&#xff0c;所以必须远程搞才行&#xff0c;今天就是安装一下&#xff0c;链接连接&#xff0c;网上有很多文章&#xff0c;能成功&#xff0c;不过我也弄了一个…

SQL——高级教程【菜鸟教程】

SQL连接 左连接&#xff1a;SQL LEFT JOIN 关键字 左表相当于主表&#xff0c;不管与右表匹不匹配都会显示所有数据 右表就只会显示和左表匹配的内容。 //例显示&#xff1a;左表的name&#xff0c;有表的总数&#xff0c;时间 SELECT Websites.name, access_log.count, acc…

GitHub Copilot Workspace:欢迎进入原生Copilot开发环境

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Vue 组件的三大组成部分

Vue 组件通常由三大组成部分构成&#xff1a;模板&#xff08;Template&#xff09;、脚本&#xff08;Script&#xff09;、样式&#xff08;Style&#xff09; 模板部分是组件的 HTML 结构&#xff0c;它定义了组件的外观和布局。Vue 使用基于 HTML 的模板语法来声明组件的模…

【Vulhub靶场】Nginx 漏洞复现

Nginx 漏洞复现 一、Nginx 文件名逻辑漏洞&#xff08;CVE-2013-4547&#xff09;1、影响版本2、漏洞原理3、漏洞复现 二、Nginx 解析漏洞1、版本信息&#xff1a;2、漏洞详情3、漏洞复现 一、Nginx 文件名逻辑漏洞&#xff08;CVE-2013-4547&#xff09; 1、影响版本 Nginx …

网际协议IP

一、概念导入 网际协议IP是TCP/IP体系中最重要的协议之一。与IP协议配套使用的还有三个协议&#xff1a; 地址解析协议ARP网际控制报文协议ICMP网际组管理协议IGMP 二、虚拟互联网络 &#xff08;1&#xff09;定义 现实世界中&#xff0c;不同网络的主机进行通信&#xf…

Centos7.9系统MySQL5.7.32升级为5.7.44(生成环境操作)

1.背景 由于客户进行等保漏扫和渗透&#xff0c;生成环境mysql数据库被扫描出了 高危漏洞。 如图&#xff1a;部分漏洞 查看漏洞详细信息&#xff0c;建议升级到指定版本解决&#xff1a; 说明&#xff1a; 本文仅适合使用当前数据库为 RPM 安装方式 2.升级前准备 查看环…

nginx的前世今生(三)

高手对决&#xff1a;武林盟主之路 1.不败之地&#xff0c;高可用江湖 技术角度讲&#xff0c;高可用&#xff08;High Availability, HA&#xff09;是指系统或服务能够在预定的时间内&#xff0c;以极高的概率持续提供服务的能力。具体来说&#xff0c;这通常涉及到系统的架…

32.Docker认识

Docker介绍 Docker是一个快速交付应用&#xff0c;运行应用的技术。 1.可以将程序、依赖、运行环境一起打包为一个镜像&#xff0c;可以迁移到任意Linux操作系统。 2.运行时利用沙箱机制行程隔离容器&#xff0c;各个应用互不干扰。 3.启动、移除都可以通过一行命令完成&am…

I2C接口18路LED呼吸灯驱动IS31FL3218互相替代SN3218替换HTR3218

I2C接口18路LED呼吸灯控制电路IC 该型号IC为QFN24接口&#xff0c;属于小众产品&#xff0c;IS31FL3218、SN3218、HTR3218S管脚兼容&#xff0c;需要注意的是HTR3218管脚与其他型号不兼容。 I2C接口可实现多个LED灯的呼吸灯控制&#xff0c;可实现单色控制18个LED灯&#xff0…

Kubernetes - Dashboard 配置用户名密码方式登录

Kubernetes - Dashboard 配置用户名密码方式登录 前言&#xff1a; 为了 K8s 集群安全&#xff0c;默认情况下 Dashboard 以 Token的形式登录的&#xff0c;那如果我们想以用户名/密码的方式登录该怎么操作呢&#xff1f;其实只需要我们创建用户并进行 ClusterRoleBinding绑定即…

Educational Codeforces Round 165 (Rated for Div. 2 ABCDE 题)视频讲解

A. Two Friends Problem Statement Monocarp wants to throw a party. He has n n n friends, and he wants to have at least 2 2 2 of them at his party. The i i i-th friend’s best friend is p i p_i pi​. All p i p_i pi​ are distinct, and for every i ∈…

并发编程之线程池的设计和原理

一、线程池 提前创建一系列的线程&#xff0c;保存在这个线程池中&#xff0c;有任务要执行的时候&#xff0c;从线程池中取出线程来执行。没有任务的时候&#xff0c;线程池放回去。 二、为什么要使用线程池 线程使用上的问题: 线程的频繁创建 和 销毁 线程的数量过多&…