一、前言

这一章的主要讲解数据库连接池是如何实现的,以及登录注册的逻辑处理。

二、数据库连接池是如何运行的

在处理用户注册,登录请求的时候,我们需要将这些用户的用户名和密码保存下载用于新用户的注册以及老用户的登录校验

若每次用户请求我们都需要新建一个数据库连接,请求结束后我们释放该数据库连接,当**用户连接过多时,这种做法过于低效,所以类似线程池**的做法,我们构建一个数据库连接池,预先生成一些数据库连接放在那里供用户请求使用。

作线程从数据库连接池取得一个连接,访问数据库中的数据,访问完毕后将连接交还连接池。

2.1 单个数据库连接是如何生成的

使用mysql_init()初始化连接
使用mysql_real_connect()建立一个到mysql数据库的连接
使用mysql_query()执行查询语句
使用result = mysql_store_result(mysql)获取结果集
使用mysql_num_fields(result)获取查询的列数,mysql_num_rows(result)获取结果集的行数
通过mysql_fetch_row(result)不断获取下一行,然后循环输出
使用mysql_free_result(result)释放结果集所占内存
使用mysql_close(conn)关闭连接

2.2 连接池实现的细节

对于一个数据库连接池来讲,就是预先生成多个这样的数据库连接,然后放在一个链表中,同时维护最大连接数MAX_CONN,当前可用连接数FREE_CONN和当前已用连接数CUR_CONN这三个变量。同样注意在对连接池操作时(获取,释放),要用到锁机制,因为它被所有线程共享。

(1) 连接池的实现:

初始化,获取连接、释放连接,销毁连接池。

将数据库连接的获取与释放通过RAII机制封装,避免手动释放。

使用信号量实现多线程争夺连接的同步机制,这里将<u>信号量初始化为数据库的连接总数。</u>(实验中设置的数量量为8,在main.c 中设计)

(2) 获取与释放连接

当线程数量大于数据库连接数量时,使用信号量进行同步,每次取出连接,信号量原子减1,释放连接原子加1,若连接池内没有连接了,则阻塞等待。另外,由于多线程操作连接池,会造成竞争,这里使用互斥锁完成同步。

(3) 销毁连接

销毁的时候没有直接被外部调用,而是通过RAII机制来完成自动释放;

通过迭代器遍历连接池链表,关闭对应数据库连接,清空链表并重置空闲连接和现有连接数量。

RAII机制

  • RAII全称是“Resource Acquisition is Initialization”,直译过来是“资源获取即初始化”.
  • RAII的核心思想是将资源或者状态与对象的生命周期绑定,通过C++的语言机制,实现资源和状态的安全管理,智能指针是RAII最好的例子
  • 具体来说:构造函数的时候初始化获取资源,析构函数释放资源

2.3 大数据访问优化

登录中的用户名和密码你是load到本地,然后使用map匹配的,如果有10亿数据,即使load到本地后hash,也是很耗时的,你要怎么优化?

数据查询的优化:保证在实现功能的基础上,尽量减少对数据库的访问次数;通过搜索参数,尽量减少对表的访问行数,最小化结果集,从而减轻网络负担;能够分开的操作尽量分开处理,提高每次的响应速度;在数据窗口使用SQL时,尽量把使用的索引放在选择的首列;算法的结构尽量简单;

三、 登录与注册

使用数据库连接池实现服务器访问数据库的功能,使用POST请求完成注册和登录的校验工作。

分为四部分内容

  1. 载入数据库表:

将数据库总的用户名和密码载入到服务器的map中来,map中的key为用户名,value为密码。

  1. 提取用户名和密码

提取用户名和密码,服务器端解析浏览器的请求报文,当解析为POST请求时,CGI标志位设置为1,并将请求报文的消息体赋值给m_string,进而提取出用户名和密码。

  1. 同步线程登录和注册

通过m_url定位/所在位置,根据/后的第一个字符判断是登录还是注册校验。

  • 2 --- 登录校验
  • 3 --- 注册校验
  1. 页面跳转

通过m_url定位/所在位置,根据/后的第一个字符,使用分支语句实现页面跳转。具体的,

  • 0 --- 跳转注册页面,GET
  • 1 --- 跳转登录页面,GET
  • 5 --- 显示图片页面,POST
  • 6 --- 显示视频页面,POST
  • 7 --- 显示关注页面,POST

6.1 各页面请求跳转的流程

图片

6.2 载入数据库

将数据库中的用户名和密码载入到服务器的map中来,map中的key为用户名,value为密码。

6.3 提取用户名和密码

服务器端解析浏览器的请求报文,当解析为POST请求时,cgi标志位设置为1,并将请求报文的消息体赋值给m_string,进而提取出用户名和密码。

6.4 同步线程登录

通过m_url定位/所在的位置,判断是登录还是注册校验

2 登录校验

3 注册校验

对数据库的操作需要通过锁来同步。

6.5 大数据量优化问题

登录中的用户名和密码你是load到本地,然后使用map匹配的,如果有10亿数据,即使l0ad到本地后hash,也是很耗时的,你要怎么优化?

1.数据结构的优化:为了保证数据库的一致性和完整性,在逻辑设计的时候往往会设计过多的表间关联,尽可能的降低数据的冗余。

2.数据查询的优化:保证在实现功能的基础上,尽量减少对数据库的访问次数;通过搜索参数,尽量减少对表的访问行数,最小化结果集,从而减轻网络负担;能够分开的操作尽量分开处理,提高每次的响应速度;在数据窗口使用SQL时,尽量把使用的索引放在选择的首列;算法的结构尽量简单;

3.对算法那的优化:尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。.使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。

4.建立高效的索引:

四、小结

数据库的连接池的设计和线程池的线程池的设计的目的是一样,减少开销,虽然系统的数据量远远达不到大数据量,但是大数据量对于服务器性能考察是非常重要的,因此设计上应该花点功夫想清楚问题!下一章重点讲解日志系统实现。

五、参考资料

  • 《两猿社》
  • 《Linux高性能服务器》