Step 4 工具类的编写-JDBCUtil、KafkaUtil、PropertiesUtil

开发过程中代码会随着开发进度进行变更,解决bug和进行优化、功能新增等

最新的代码可以再Gitee中获取:SparkStreamingDemand: 完整的sparkStreaming项目开发代码记录

 1 PropertiesUtil

用来加载配置数据资源包

1.1 PropertiesUitl编写

package SparkStreamingProject.util

import java.io.InputStreamReader
import java.util.Properties

object PropertiesUtil {
 def load(propertiesName: String): Properties = {
  val prop = new Properties()
  prop.load(
   new InputStreamReader(
     Thread.currentThread().getContextClassLoader.getResourceAsStream(propertiesName), "UTF-8"
    )
  )
  prop
 }
}

1.2生成资源包的方法

1.3 使用工具类加载资源包的方式 

不带路径直接填文件名(在JDBCUtil类中有使用)

  val config: Properties = PropertiesUtil.load("config.properties")

1.4 加载config.properties时出现空指针异常

1.4.1 加载资源包代码:

Thread.currentThread().getContextClassLoader().getResourceAsStream("config.properties")

1.4.2 出现的报错:

Exception in thread "main" java.lang.NullPointerException

原因:config.properties需要放在资源目录下,且如果是maven项目,资源包的路径其实是

target/classes/config.properties

工程目录src/main/resources下的文件一般在编译后是会自动复制到target/classes目录下的,这时候需要检查一下资源包路径和target/classes路径下是否有config.properties

 1.4.3 解决办法

1.4.3.1 step1 在maven的pom依赖中增加以下配置
<resources>
  <resource>
    <directory>src/main/resources</directory>
    <includes>
      <include>**/*.properties</include>
      <include>**/*.xml</include>
    </includes>
    <filtering>true</filtering>
  </resource>
</resources>
1.4.3.2 step2 在src下建立resource资源包文件夹,并标记为资源根目录

(增加了上面的pom依赖后这一步就不用做,可以检查一下是否标记成功,如果未设置成功就手动设置下)

 1.4.3 step3 资源包不要带任何路径,因为已经设置好资源根路径

1.4.4  idea中生成properties文件的方式

2 JDBCUtil

获取mysql返回值,使用方式见本文第四章节Dao层对kafka和mysql的操作

package SparkStreamingProject.util
import com.alibaba.druid.pool.DruidDataSourceFactory

import java.sql.Connection
import java.util.Properties
object jdbcUtil {
 
 
 def mysqlConnect(): Connection = {
  val properties = new Properties()
  val config: Properties = PropertiesUtil.load("config.properties")
  properties.setProperty("driverClassName", "com.mysql.jdbc.Driver")
  properties.setProperty("url", config.getProperty("jdbc.url"))
  properties.setProperty("username", config.getProperty("jdbc.user"))
  properties.setProperty("password", config.getProperty("jdbc.password"))
  properties.setProperty("maxActive",
   config.getProperty("jdbc.datasource.size")
  )
  //获取 MySQL 连接
  DruidDataSourceFactory.createDataSource(properties).getConnection
 }
}

3 KafkaUtil

createKafkaProducer()获取kafkaProductor--生产者

getKafkaPara() --获取消费者的kafka链接

使用方式见第四章节Dao层对kafka和mysql的操作

package SparkStreamingProject.util

import org.apache.kafka.clients.producer.{KafkaProducer, ProducerConfig}
import org.apache.kafka.common.serialization.StringDeserializer

import java.util.Properties

object KafkaUtil {
 a
 def getKafkaPara(topicName: String): Map[String, Object] = {
  val config: Properties = PropertiesUtil.load("config.properties")
  val broker_list: String = config.getProperty("kafka.broker.list")
  val kafkaPara = Map(
   "bootstrap.servers" -> broker_list,
   "key.deserializer" -> classOf[StringDeserializer],
   "value.deserializer" -> classOf[StringDeserializer],
   //消费者组
   "group.id" -> topicName,
   //如果没有初始化偏移量或者当前的偏移量不存在任何服务器上,可以使用这个配置属性
   //可以使用这个配置,latest 自动重置偏移量为最新的偏移量
   "auto.offset.reset" -> "latest",
   //如果是 true,则这个消费者的偏移量会在后台自动提交,但是 kafka 宕机容易丢失数据
   //如果是 false,会需要手动维护 kafka 偏移量
   "enable.auto.commit" -> (true: java.lang.Boolean)
  )
  kafkaPara
 }
 //获取kafkaProductor
 def createKafkaProducer(): KafkaProducer[String, Any] = {
  val config: Properties = PropertiesUtil.load("config.properties")
  val prop = new Properties()
  // 添加配置
  prop.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, config.getProperty("kafka.broker.list"))
  prop.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer")
  prop.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer")
  // 根据配置创建 Kafka 生产者
  new KafkaProducer[String, Any](prop)
 }

}

4 更新Dao层对kafka和mysql的操作

4.1 kafka

4.1.1 获取指定主题的kafka数据流,返回字符数据流--消费者

def getKafkaData(topicName:String): InputDStream[ConsumerRecord[String, String]]  = {
 //定义 Kafka 参数
 val kafkaPara: Map[String, Object] = getKafkaPara(topicName)
 val inputDStream: InputDStream[ConsumerRecord[String, String]] =
  KafkaUtils.createDirectStream[String, String](
  sscGet(),
   //ssc,
  LocationStrategies.PreferConsistent,
  ConsumerStrategies.Subscribe[String, String](Set(topicName), kafkaPara)
 )
 inputDStream
}

4.1.2 生产数据到kafka --生产者

def setDataToKafka(topicName:String,data:Any): Unit = {
 val record: ProducerRecord[String, Any] = new ProducerRecord[String, Any](topicName, data)
 val producer: KafkaProducer[String, Any] = createKafkaProducer()
 producer.send(record)
}

4.2 mysql

4.2.1 执行 SQL 语句,单条数据插入和更新

返回布尔值成功与否

	
	//执行 SQL 语句,单条数据插入和更新,返回布尔值成功与否
	/*
	* 举例 insert into mytable(?,?)
	*         数据:array(1,2)
	*         插入一条
	* */
	def executeOneData(mysqlConn:Connection,sql:String,data:Array[Any],debugFlag:Boolean=false): Int = {
		var  resultCnt=0
		try {
			//设置不自动 Commit参数
			mysqlConn.setAutoCommit(false)
			//预编译SQL语句,设置参数
			val statement: PreparedStatement = mysqlConn.prepareStatement(sql)
			//设置第一个参数
			if (data != null && !data.isEmpty) {
				for (i <- data.indices) {
					statement.setObject(i + 1, data(i))
				}
			}
			statement.addBatch()
			if (debugFlag) {
				print(s"\n$sql: => (${data.mkString(",")})")
			}
			//批量执行,返回每个执行的条数
			val counts = statement.executeBatch()
			//提交刚才的更新
			mysqlConn.commit
			statement.close()
			resultCnt=counts.sum
		}catch {
			case e: Exception => e.printStackTrace()
		}
		resultCnt
	}

4.2.2 执行 SQL 语句,批量数据插入

第三个参数为debug开关,打开后会打印

	
	//执行 SQL 语句,批量数据插入,第三个参数为debug开关,打开后会打印
	/*举例 insert into mytable(?,?)
						数据:Array(Array(1,0),Array(2,1))
						插入两条
	* 举例 update table
			*     set col1=?
			*     where col2=?
			*     数据:Array(Array(1,0),Array(2,1));
			*     更新col1=1的数据的col2=0
			*     更新col1=2的数据的col2=1
	* */
	def executeBatch(mysqlConn:Connection,sql: String, dataList:Iterator[Array[Any]] ,debugFlag:Boolean=false): Int = {
		
		var  resultCnt=0
		try{
			//设置不自动 Commit参数
			mysqlConn.setAutoCommit(false)
			//预编译SQL语句,设置参数
			val statement: PreparedStatement = mysqlConn.prepareStatement(sql)
			//设置第一个参数
			for(data<-dataList) {
				if (data != null && !data.isEmpty) {
					//debug//
					if (debugFlag) {
						data.mkString(",")
						print(s"\n$sql: => (${data.mkString(",")})")
					}
					for (i <- data.indices) {
						statement.setObject(i+1, data(i))
					}
					statement.addBatch()
				}
			}
			if (debugFlag){
				println()
			}
			
			//批量执行,返回每个执行的条数//批量执行,返回执行的总条数
			val counts: Array[Int] = statement.executeBatch()
			//提交刚才的更新
			mysqlConn.commit
			statement.close()
		if (dataList.length!=0) {
			resultCnt=counts.sum/dataList.length
		}else {
			resultCnt=counts.sum
		}
			statement.close()
		} catch
		{
			case e: Exception => e.printStackTrace()
		}
		//debug//
		if(debugFlag) {
			println(s"插入条数:$resultCnt")
		}
		resultCnt
	}

4.2.3 判断一条数据是否存在

def dataIsExist(sql: String, data:Array[T]): Boolean = {
 var result = false
 try {
  //设置不自动 Commit参数
  mysqlConn.setAutoCommit(false)
  //预编译SQL语句,设置参数
  val statement: PreparedStatement = mysqlConn.prepareStatement(sql)

  if (data != null && !data.isEmpty) {
   for (i <- data.indices) {
    statement.setObject(i + 1, data(i))
   }
  }
  result = statement.executeQuery().next()
  
  statement.close()

 } catch {
  case e: Exception => e.printStackTrace()
 }
 result
}

4.2.4 查询数据操作返回条数

def dataCnt(sql: String, data: Array[T]): Long = {
 var resultCnt:Long=0
 try {
  //设置不自动 Commit参数
  mysqlConn.setAutoCommit(false)
  //预编译SQL语句,设置参数
  val staatement: PreparedStatement = mysqlConn.prepareStatement(sql)
  if (data != null && !data.isEmpty) {
   for (i <- data.indices) {
    statement.setObject(i + 1, data(i))
   }
  }
  val result: ResultSet = statement.executeQuery()
  while (result.next()) {
   resultCnt = result.getLong(1)
  }
 } catch {
  case e: Exception => e.printStackTrace()
 }
 resultCnt
}

4.2.5 获取 MySQL 数据

传入limit参数,返回limit条数据,数据形式为二维数组,如果limit=-1则返回所有的数据

	//获取 MySQL 数据,传入limit参数,返回limit条数据,数据形式为二维数组,如果limit=-1则返回所有的数据
	def getData(mysqlConn:Connection,sql: String, data: Array[Any],limit:Int=1,debugFlag:Boolean=false): Array[Array[Any]] = {
		var resultList: List[Array[Any]] = List()
		if (debugFlag){
			println(s"查询sql=$sql\t[${data.mkString(",")}]\tlimit ${limit}")
		}
		try {
			//设置不自动 Commit参数
			mysqlConn.setAutoCommit(false)
			//预编译SQL语句,设置参数
			val statement: PreparedStatement = mysqlConn.prepareStatement(sql)
			if (data != null && !data.isEmpty) {
				for (i <- data.indices) {
					statement.setObject(i + 1, data(i))
				}
			}
			val result: ResultSet = statement.executeQuery()
			if (limit == -1){
				while (result.next()) {
					var list: Array[Any] =Array.empty
					for (i <- 1 to result.getMetaData().getColumnCount) {
						list :+= result.getObject(result.getMetaData().getColumnName(i)).toString
					}
					resultList=resultList :+ list
				}
			}else {
				while (result.next()) {
					for (j <- 1 to limit) {
						var list: Array[Any] =Array.empty
						for (i <- 1 to result.getMetaData().getColumnCount) {
							list :+= result.getObject(result.getMetaData().getColumnName(i)).toString
						}
						resultList=resultList :+ list
					}
				}
			}
			if (debugFlag) {
				val result = resultList.map { arr =>
					if (arr.length == 1) arr.mkString
					else arr.mkString(s"查询的数据:[", ", ", "]")
				}.mkString("\n")
				println(result)
			}
			result.close()
			statement.close()
		} catch {
			case e: Exception => e.printStackTrace()
		}
		resultList.toArray
	}
	

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值