package sparkstreaming
import java.util.Properties
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.{SparkConf, SparkContext}
import poolutils.MysqlPool
object Spark_Mysql extends App{
val conf = new SparkConf().setAppName("demo").setMaster("local[*]")
val sc = new SparkContext(conf)
val ssc = new StreamingContext(sc,Seconds(5))
//读取配置文件
val pro = new Properties()//配置项
pro.put("jdbc","jdbc://localhost:3306/iql?user=root&password=root")
val pool = MysqlPool(pro)//这里调用了 mysqlpool的 GenericObjectPool方法,返回一个可以管理的对象池的所有操作
//即创建对象,销毁对象,借出对象的一系列操作
//创建一个Socket输入流,
ssc.socketTextStream("localhost",12345).foreachRDD(rdd=>{
rdd.foreach(f=>{
//borrowObject方法就是:拿到一个MysqlProxy实例
val mysqlProxy = pool.borrowObject()//====这里是线程池操作
val con = mysqlProxy.conn//获取连接
//预编译,
//需要执行Statement对象多次的时候,PreparedStatement对象将会大大降低运行时间,当然也加快了访问数据库的速度
val cs = con.prepareStatement("insert into s values (?)")//===从这里开始都是mysql数据操作
//给第一个问好赋值为f
cs.setString(1,f)
//execute 方法返回一个 boolean 值,判断第一个结果的形式
// 如果是查询的话返回true,如果是更新或插入的话就返回false了;
cs.execute()
cs.close()//===到这里结束 数据库操作结束
//returnObject方法:归还对象到线程池
pool.returnObject(mysqlProxy)//===这里是线程池操作
}
)
})
ssc.start()
ssc.awaitTermination()
}
======================================
package sparkstreaming.poolutils
import java.sql.DriverManager
import java.util.Properties
import org.apache.commons.pool2.{BasePooledObjectFactory, PooledObject}
import org.apache.commons.pool2.impl.{DefaultPooledObject, GenericObjectPool, GenericObjectPoolConfig}
import poolutils.HBasePool
/**
* 基于commons-pool2编写MySQL的连接池
* GenericObjectPool <T> 实现了ObjectPool<T> 具备对象池的功能,
* 同时 继承了BaseGenericObjectPool<T> 的对于对象状态管理和回收等功能
* 构造函数通过GenericObjectPoolConfig 和PooledObjectFactory来进行参数的初始化和对象工厂类的引入
*
* 自我理解
* 1首先我们拿到了一个传来的mysql的jdbc连接,然后我们使用一个方法MysqlProxy连接上我们的mysql,在里面我们提供了shutdown的方法方便后面使用
* 2.我们创建了继承了BasePooledObjectFactory的一个MysqlProxyFactory方法,里面我们只需要实现来个方法即create和wrap方法,当然我们自己实现了
* 一个销毁的方法destroyObject(这里我还不清楚用在什么时候).
* 3.以上的步骤都是为了我们的apply的方法,里面的一个类是GenericObjectPool(很重要),这里我们需要俩个参数
* 分别是连接池的一个配置属性的方法(GenericObjectPoolConfig)和一个对连接池的创建,删除和销毁的方法(MysqlProxyFactory)
* 当我们拿到了 以上俩个参数后 我们即可返回给Spark_Mysql一个连接池的实例pool
*
* GenericObjectPool:采用LIFO/FIFO结构实现ObjectPool接口,池的默认行为是一个LIFO,这就意味着,当池中有空闲可用的对象时,调用borrowObject方法会返回最近(“后进”)的实例.
* 如果LIFO策略在池中是false的,实例的返回按相反的顺序,-先进 - 先出.(这里我们没有配置所以是lifo结构)(主要的就是使用的这个功能!!)
*
* GenericObjectPool的构造方法共有七个,最简单的一个是GenericObjectPool(PoolableObjectFactory factory).仅仅指明要用的PoolableObjectFactory实例,其它参数则采用默认值(这里我们用的实例是MysqlProxy类)
*
*/
object MysqlPool {
//第三步,GenericObjectPool实现了线程池中的对象回收和管理等功能,这里我们先建立一个实例,用于返回给Spark_Mysql类的调用
private var pool:GenericObjectPool[MysqlProxy]=_
def apply(pro:Properties):GenericObjectPool[MysqlProxy]={//这里传来的参数就是"jdbc","jdbc://localhost:3306/iql?user=root&password=root"
HBasePool.synchronized{
if (null == pool){
//①这里是GenericObjectPool的参数之一,传来参数为"jdbc","jdbc://localhost:3306/iql?user=root&password=root"
val poolFactory = new MysqlProxyFactory(pro)//在这里我们拿到了工厂的实例,即可以创建(create),包装(wrap),销毁(destroyObject)
//②这里是GenericObjectPool的参数之二,我们要配置的连接池的属性,
val poolConfig={
//参数的初始化
val c = new GenericObjectPoolConfig
//最大连接数,默认为8
c.setMaxTotal(5)
//最大空闲链接数,默认也为8
c.setMinIdle(5)
c
}
//③此时我们已经将俩参数 MysqlProxyFactory(pro) 和 GenericObjectPoolConfig添加到GenericObjectPool 即拿到了实例,然后返回给调用者
pool = new GenericObjectPool[MysqlProxy](poolFactory,poolConfig)//①② GenericObjectPool实例,GenericObjectPool类已经实现了和对象池有关的所有核心操作,开发者可以通过继承或者封装的方式来使用它.通过此构造函数,
// 我们能够清晰的看到,一个Pool中需要指定PoolableObjectFactory 实例,以及此对象池的Config信息.PoolableObjectFactory主要用来"创建新对象",比如当对象池中的对象不足时,可以使用 PoolableObjectFactory.makeObject()方法来创建对象,并交付给Pool管理.
//此构造函数实例化了一个LinkedList作为"对象池"容器,用来存取"对象".此外还会根据timeBetweenEvictionRunsMillis的值来决定是否启动一个后台线程,此线程用来周期性扫描pool中的对象列表,已检测"对象池中的对象"空闲(idle)的时间是否达到了阀值,如果是,则移除此对象.
}
pool
}
}
}
//第一步先是获取了连接创建driver驱动,
case class MysqlProxy(pro:Properties) {
lazy val conn = {//懒加载机制 调用时启动 此步骤为拿到jdbc的连接
//获取jdbc连接
classOf[com.mysql.jdbc.Driver] //反射机制 拿到连接mysql的实例
//getProperty方法:用指定的键在此属性列表中搜索属性(value)
val jdbc = pro.getProperty("jdbc")
//DriverManager是驱动的管理类,通过重载的getConnection()方法获取数据库连接,较为方便
DriverManager.getConnection("jdbc")//连接到mysql
}
//关闭客户端
def shutdown()= {conn.close()}//这里提供一个shutdown的方法在工厂中被调用,后期被apply方法使用以传回实例给Spark_Mysql使用
}
/*第二步
注解 先创建工厂的实例
@PooledObjectFactory,是一个池化对象工厂接口,定义了生成对象、激活对象、钝化对象、销毁对象的方法
如果需要使用Commons-Pool,那么你就需要提供一个PooledObjectFactory接口的具体实现
一个比较简单的办法就是,继承BasePooledObjectFactory这个抽象类,而继承这个抽象类,只需要实现两个方法:create()和wrap(T obj)
实现create()方法很简单,而实现wrap(T obj)也有捷径,可以使用类DefaultPooledObject
此MysqlProxyFactory方法继承 BasePooledObjectFactory的目的是为了生成,激活,钝化,和销毁对象的方法,
这里我们只需要实现一个create方法和wrap方法 还有一个销毁的方法 目的是为了后续的使用(这里我还不确定在哪里使用)
*/
class MysqlProxyFactory(pro:Properties)extends BasePooledObjectFactory[MysqlProxy]{//泛型为mysqlproxy
//实现create方法:创建一个MySQLproxy实例
override def create(): MysqlProxy = MysqlProxy(pro)
//对实例进行封装
override def wrap(obj: MysqlProxy): PooledObject[MysqlProxy] = new DefaultPooledObject[MysqlProxy](obj)
//归还对象到线程池是通过returnObject方法实现,简单而言就是先调用validateObject方法判断该对象是否是可用的,
// 如果可用则归还到池中,LinkedList容器加一,如果是不可以的则则调用destroyObject方法进行销毁。
override def destroyObject(p: PooledObject[MysqlProxy]): Unit = {
p.getObject.shutdown()
super.destroyObject(p)
}
}
==========================================
package poolutils
import org.apache.commons.pool2.{ BasePooledObjectFactory, PooledObject}
import org.apache.commons.pool2.impl.{DefaultPooledObject, GenericObjectPool, GenericObjectPoolConfig}
import org.apache.hadoop.hbase.{HBaseConfiguration, TableName}
import org.apache.hadoop.hbase.client.{ConnectionFactory, Table}
//habse和mysql一个套路 ...
object HBasePool {
private var pool:GenericObjectPool[HBaseProxy]= _
def apply (quorum:String ,port:String ):GenericObjectPool[HBaseProxy]={
HBasePool.synchronized{
if (null == pool){
val poolFactory = new HBaseProxyFactory(quorum,port)
val poolConfig = {
val c = new GenericObjectPoolConfig
//最大连接数
c.setMaxTotal(5)
//最大空闲连接数
c.setMaxIdle(5)
c
}
pool = new GenericObjectPool[HBaseProxy](poolFactory,poolConfig)
}
pool
}
}
}
case class HBaseProxy(quorum:String ,port:String){
//懒加载连接,调用时启动
lazy private val conn ={
val config = HBaseConfiguration.create()
config.set("hbase.zookeeper.quorum", quorum)
config.set("hbase.zookeeper.property.clientPort", port)
//
ConnectionFactory.createConnection(config)
}
//获得表:
def getTable (tablename :String ):Table ={
conn.getTable(TableName.valueOf(tablename))
}
//关闭客户端
def shutdown():Unit=conn.close()
}
//这个类是创建池的对象的工厂类
class HBaseProxyFactory(quorum: String, port: String)extends BasePooledObjectFactory[HBaseProxy]{
//创建实体:
override def create(): HBaseProxy = HBaseProxy(quorum,port)
//包装实体
override def wrap(obj: HBaseProxy): PooledObject[HBaseProxy] = new DefaultPooledObject[HBaseProxy](obj)
override def activateObject(p: PooledObject[HBaseProxy]): Unit = {
p.getObject.shutdown()
super.activateObject(p)
}
}