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 = conn
    val statement: PreparedStatement = pst(connect)
    // 过程级增删改查(数据记录):INSERT DELETE UPDATE SELECT
    // 对象级增删改查(对象——表、视图、索引):CREATE DROP ALTER SHOW
    sql 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 recovery

import java.sql.{Connection, DriverManager, PreparedStatement, ResultSet, SQLException}
import scala.collection.mutable.ArrayBuffer
import scala.reflect.ClassTag

object 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 = conn
      val statement: PreparedStatement = pst(connect)
      // 过程级增删改查(数据记录):INSERT DELETE UPDATE SELECT
      // 对象级增删改查(对象——表、视图、索引):CREATE DROP ALTER SHOW
      sql 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.结果

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/589338.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

53.HarmonyOS鸿蒙系统 App(ArkTS) socket套接字连接失败无效参数--invalid argument

ark ts socket套接字连接失败无效参数--invalid argument 绑定本机真实连接的WIFI的IP&#xff0c;不要绑定127.0.0.1

云原生Kubernetes: K8S 1.29版本 部署Harbor

目录 一、实验 1.环境 2.Linux 部署docker compose 3.证书秘钥配置 4.K8S 1.29版本 部署Harbor 5.K8S 1.29版本 使用Harbor 二、问题 1.docker 登录harbor失败 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 主机架构版本IP备注masterK8S master节点1.2…

Debian操作系统的常用指令介绍

Debian是一个流行的Linux操作系统&#xff0c;以其稳定性和安全性而闻名。对于Debian用户来说&#xff0c;掌握一些基本的命令行指令是非常重要的&#xff0c;因为它们可以帮助你更高效地管理系统。在这篇博客中&#xff0c;我们将介绍一些在Debian系统中常用的指令及其功能。 …

79、贪心-跳跃游戏II

思路&#xff1a; 首先理解题意&#xff1a;从首位置跳最少多少次到达末尾。 第一种&#xff1a;使用递归&#xff0c;将所有跳转路径都获取到进行求出最小值。 第二种&#xff1a;使用动态规划&#xff0c;下一次最优取决上一次的最优解 第三针&#xff1a;贪心&#xff…

区块链 | IPFS 工作原理入门

&#x1f98a;原文&#xff1a;What is the InterPlanetary File System (IPFS), and how does it work? &#x1f98a;写在前面&#xff1a;本文属于搬运博客&#xff0c;自己留存学习。 1 去中心化互联网 尽管万维网是一个全球性的网络&#xff0c;但在数据存储方面&#…

智能消费记账|基于SSM+vue的大学生智能消费记账系统(源码+数据库+文档)

智能消费记账目录 基于SSMvue的大学生智能消费记账系统 一、前言 二、系统设计 三、系统功能设计 1 用户列表 2 预算信息管理 3 预算类型管理 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1…

R语言的学习—5—多元数据直观表示

1、数据读取 ## 数据整理 d3.1read.xlsx(adstats.xlsx,d3.1,rowNamesT);d3.1 #读取adstats.xlsx表格d3.1数据 barplot(apply(d3.1,1,mean)) #按行做均值条形图 barplot(apply(d3.1,1,mean),las3) barplot(apply(d3.1,2,mean)) #按列做均值图条形图 barplot(a…

Web,Sip,Rtsp,Rtmp,WebRtc,专业MCU融屏视频混流会议直播方案分析

随着万物互联&#xff0c;视频会议直播互动深入业务各方面&#xff0c;主流SFU并不适合管理&#xff0c;很多业务需要各种监控终端&#xff0c;互动SIP硬件设备&#xff0c;Web在线业务平台能相互融合&#xff0c;互联互通&#xff0c; 视频混流直播&#xff0c;录存直播推广&a…

手撕C语言题典——合并两个有序数组(顺序表)

搭配食用更佳哦~~ 数据结构之顺顺顺——顺序表-CSDN博客 数据结构之顺序表的基本操作-CSDN博客 继续来做一下关于顺序表的经典算法题叭~ 前言 88. 合并两个有序数组 - 力扣&#xff08;LeetCode&#xff09; 合并数组也是力扣上关于顺序表的一道简单题&#xff0c;继续来加深…

字节缓冲流

BufferedInputStream() 该类实现缓冲流输出对象&#xff08;可以向底层输出流写入字节而不必为写入的每一个字节导致底层系统的调用&#xff09; BufferedOutputStream() 创建BufferedOutputStream()将创建一个内部缓冲数组 当从流中读取或跳过字节时&#xff0c;内部缓冲区根…

Kubernetes学习笔记06

第十六章、Kubernetes容器交付介绍 如何在k8s集群中部署Java项目 容器交付流程 开发代码阶段 编写代码编写Dockerfile【打镜像做准备】持续交付/集成 代码编译打包制作镜像上传镜像仓库应用部署 环境准备PodServiceIngress运维 监控故障排查应用升级 k8s部署Java项目流程 …

云服务器+ASF实现全天挂卡挂时长

目录 前言正文1.安装下载2.编辑配置文件3.设置Steam社区证书4.启动ASF5.给游戏挂时长6.进阶-ASF自动启动且后台保活 前言 我遇到的最大的问题是&#xff0c;网络问题 其实不然&#xff0c;各大厂商的云服务器后台都有流量监控&#xff0c;意味着依靠一般方法是不能正常访问St…

高手的黑箱:AI时代学习、思考与创作

课程目录 01 不要错过这个时代的巨大红利&#xff0c;AI时代竞争力养成指南.mp4 02 解密高手的黑箱——那些创作高手不告诉你的事.mp4 03 创作&#xff1a;人生发展中最重要的事.mp4 04 创作中最重要的事&#xff08;1&#xff09;&#xff1a;对过程的掌控力.mp4 05 创作…

更深层次理解传输层两协议【UDP | TCP】【UDP 缓冲区 | TCP 8种策略 | 三次握手四次挥手】

博客主页&#xff1a;花果山~程序猿-CSDN博客 文章分栏&#xff1a;Linux_花果山~程序猿的博客-CSDN博客 关注我一起学习&#xff0c;一起进步&#xff0c;一起探索编程的无限可能吧&#xff01;让我们一起努力&#xff0c;一起成长&#xff01; 目录 再谈端口号 端口号的返回…

springBootAdmin监控

简介 用于对 Spring Boot 应用的管理和监控。可以用来监控服务是否健康、是否在线、以及一些jvm数据等等 Spring Boot Admin 分为服务端(spring-boot-admin-server)和客户端(spring-boot-admin-client)&#xff0c;服务端和客户端之间采用 http 通讯方式实现数据交互&#xf…

【设计模式】创建者模式之 工厂方法 抽象工厂

工厂方法模式(Factory Method) 一个特定功能&#xff0c;往往有多种实现方式&#xff0c;但是很难有某一个实现可以适用于所有情况&#xff0c;因此往往需要根据特定的场景选择不同的实现。试想&#xff1a;把选择具体实现的代码放在业务中会发生什么&#xff1f;每当我们需要…

【C++】vector类的增删改查模拟实现(图例超详细解析!!!)

目录 一、前言 二、源码引入 三、vector的模拟实现 ✨实现框架 ✨前情提要 ✨Member functions —— 成员函数 ⚡构造函数 ⭐无参构造 ⭐迭代器区间构造 ⭐n个值构造 ⚡拷贝构造 ⚡运算符赋值重载 ⚡析构函数 ✨Element access —— 元素访问 ⚡operator[ ] …

一文全面了解 wxWidgets 布局器(Sizers)

目录 Sizers背后的理念 共同特征 最小大小 边框 对齐方式 伸缩因子 使用 Sizer 隐藏控件 wxBoxSizer wxStaticBoxSizer wxGridSizer wxFlexGridSizer 布局器&#xff08;Sizers&#xff09;&#xff0c;由wxWidgets类层次结构中的wxSizer类及其派生类表示&#xff0…

电商核心技术揭秘四十五:营销与广告策略(下)

相关系列文章 电商技术揭秘相关系列文章合集&#xff08;1&#xff09; 电商技术揭秘相关系列文章合集&#xff08;2&#xff09; 电商技术揭秘相关系列文章合集&#xff08;3&#xff09; 电商技术揭秘四十一&#xff1a;电商平台的营销系统浅析 电商技术揭秘四十二&#…

苹果可能将OpenAI技术集成至iOS/iPadOS 18

&#x1f989; AI新闻 &#x1f680; 苹果可能将OpenAI技术集成至iOS/iPadOS 18 摘要&#xff1a;苹果正在与OpenAI就将GPT技术部署在iOS/iPadOS 18中进行谈判。这项技术被视为可能增强的Siri功能&#xff0c;即“AI聊天机器人”。除Siri外&#xff0c;新技术还可能改善Spotl…