我的C++数据库访问类

一、概述

在我参与的多个项目中,大家使用libMySQL操作MySQL数据库,而且是源码即复用,在多个项目中有多套相同或相似的源码,这样的复用方式给开发带来了不变,而且libMySQL的使用比较麻烦,要应对很多的细节,很容易出错。

我要写一个动态链接库,将对libMySQL的操作封装起来,以二进制复用代替源码级复用;要提供线程安全的接口,用户无需关系是否加锁这样细节性的问题,减少出错及死锁的机会,当然也要允许用户自己选择是否线程安全的访问数据库;要简化访问数据库的流程,接口越简单越好。

我从2011年开始写这个库,我给它起名字叫HiDB。HiDB从2011年到现在,经历了一个由简到繁又有繁到简的过程,中间也包含了自己对程序理解的变化。

很多的考虑看起来很细碎,例如代码的注释风格(选择我们一贯的注释风格还是doxygen的注释风格,代码大全中也讲到了注释风格。是否需要借鉴);代码的命名规范(匈牙利命名法还是Java,C#的命名法,还有很多开源项目的命名规范);C++设计新思维中讲到Policy classes,是否可以应用到这个库中;Effective C++中讲的接口与实现分离。

这些年自己考虑过的一些东西包括注释风格的选择(我们一贯的注释,doxygen的注释风格,代码大全中也讲到了注释风格),出错时是使用错误码报出错误还是使用异常报出错误?C++设计新思维中讲的Policy classes,Effective C++中讲的接口与实现分析(Impl)

二、接口

(一)接口概述

首先确定一下HiDB的接口。该库对外显示为一个HiDB类,该类应该包含的接口包括:

1: 用户选择线程安全还是非线程安全

2: 打开数据库连接

3: 关闭数据库连接

4: 执行insert,update等非查询操作的接口(ExecuteNoQuery)

5: 获得查询结果第一行第一列的接口(ExecuteScaler)

6: 获得一次查询的所有记录(多行多列)的接口(ExecuteQuery)

7: 执行事务的接口(OnTransaction)

所有的接口都在产生异常时抛出,需要对异常做一个封装,这个异常中最好能标识出异常产生的位置,异常的编号,异常的描述,引起异常的SQL语句。我设计的异常如下:


/** @brief 数据库操作异常 */

class HI_DB_EXPORT HiDBException

{

public:

	HiDBException();

public:

	std::string ToSrting();

public:

	std::string		m_sql;			/**<  本次操作的SQL语句 */

	std::string		m_descript;		/**<  异常描述 */

	std::string		m_position;		/**<  异常位置 */

	long			m_errorId;		/**<  异常编号 */

	HiDBType		m_dbTyp;		/**<  数据库类型 */

};

为了方便的抛出异常,我提供了一个宏(这个宏只有HiDB库使用)


/** @brief 异常语句宏 */

#define HiDBHelperOnError(ps, script,sql, id) \

	HiDBException exception;\

	exception.m_position = ps;\

	exception.m_descript = script;\

	exception.m_sql = sql;\

	exception.m_errorId = id;\

	throw exception;\

	//return false;

提供该宏,除了简化用户输入外,还有一个想法就是如果用户不想使用异常,可以修改该宏,例如返回false。

熟悉ADO.NET的朋友应该可以看出这些接口是借鉴了ADO.NET的。

(二)具体接口

<1> 构造函数

本来在《C++设计新思维》中,有个Policy classes,适合这种根据用户需要提供安全或非安全接口的需求,但是Policy classes适合模板,不适合非模板,所以在这儿就没有使用,只是在构造函数中添加了一个布尔参数isUsingLock,如果为true则提供线程安全接口,否则接口是非线程安全的。

HiDB打算在将来除支持MySQL外,还支持其他数据库,所以在构造函数中,除isUsingLock外,还有一个选择数据库类型的接口。

将数据库类型写成枚举,则枚举为:


/** @brief 数据库类型 */

enum HiDBType

{

	HiDBType_Invail,	/**<  无效类型 */

	HiDBType_MySQL,	/**<  MySQL */

};

构造函数的声明就明确下来了:


   /**

	*   @brief 构造函数

	*	@param[in] type			数据库类型

	*	@param[in] isUsingLock	是否需要使用互斥锁

	*/

	HiDB(HiDBType type = HiDBType_MySQL, bool isUsingLock = false);

<2>打开数据库连接

打开数据库连接比较简单:


	/**

	*   @brief 打开数据库连接

	*	@param[in] conn			数据库连接字符串

	*   @retval true:成功,false;失败

	*   @par 实例:

	*   @code

	*	HiDB db;

	*	if (db.Open("host=127.0.0.1;port=3306;dbname=test;user=root;pwd=root;charset=gbk;"))

	*	{

	*		// 打开成功

	*	}

	*	else

	*	{

	*		// 打开失败

	*	}

	*   @endcode

	*/

	bool Open(const char* conn) throw (HiDBException);

该接口的conn参数是一个字符串,这样字符串就具有扩展性,可以针对不同的数据库,进行不同的处理(这一点感觉不是很好,但是能提供接口的稳定性)。不同数据库,需要满足特定的格式,在MySQL中,要使用类似于“host=127.0.0.1;port=3306;dbname=test;user=root;pwd=root;charset=gbk;”的格式。

<3> 关闭数据库连接


	/**

	*   @brief 关闭据库连接

	*/

	void Close(void);

<4> IsOpen接口

这个接口是延伸出来的,既然有open,close,提供一个IsOpen好像也是应该的,让用户了解当前的打开状态。


	/**

	*   @brief 数据库连接是否打开

	*/

	bool IsOpen();

<5> 执行非查询语句接口

执行SQL语句的接口,应该可以接收可变参数,除可变参数外,还应该有一个包含sql语句的字符串参数,所以接口定义如下:


	/**

	*   @brief 执行SQL语句,并不返回结果

	*	@param[in] conn			SQL语句

	*   @retval true:成功,false;失败

	*   @par 实例:

	*   @code

	*	HiDB db;

	*	if (db.ExecuteNoQuery("UPDATE table SET Paramer1=‘%s‘ 

	*		and Paramer2=‘%s‘ OR Paramer3=%d", "test1", "test2", 3))

	*	{

	*		// 执行成功

	*	}

	*	else

	*	{

	*		// 执行失败

	*	}

	*   @endcode

	*/

	bool ExecuteNoQuery(const char* sql, ...) throw (HiDBException);

<6> 获得查询结果第一行第一列的接口

该接口的参数与执行非查询语句的接口一致,但是返回值应该为字符串,如果执行失败,则应该返回空字符串。触发异常时,抛出HiDBException异常。


   /**

	*   @brief 执行SQL语句,返回一个结果

	*	@param[in] sql			SQL语句

	*   @retval 获得的数据,如果为空,则失败

	*/

	std::string ExecuteScalar(const char* sql, ...) throw (HiDBException);

<7> 获得一次查询的所有记录(多行多列)的接口

该接口的参数与执行非查询语句的接口一致。

返回结果应该是包含多行多列的一个数据集,在ADO.NET中有DataTable,在这儿,我们可以用stl中的vector存储多行,map存储每行数据的多列。

多以需要定义一个数据集:


#ifndef HiDBTable



typedef std::map<std::string, std::string> HiDBMap;



/** @brief 查询结果 */

typedef std::vector<HiDBMap> HiDBTable; /**<  查询结果 */

#endif

因为HiDBTable中包含多个map,所以最好避免拷贝,使用stl的shared_ptr来避免多次拷贝:


	/**

	*   @brief 执行SQL语句,返回一个结果集合

	*	@param[in] sql			SQL语句

	*   @retval 存储查询记录的智能指针

	*/

	std::shared_ptr<HiDBTable> ExecuteQuery(const char* sql, ...) throw (HiDBException);

<8> 执行事务的接口

执行事务接口是一个Command模式的接口,参数应该是一个函数对象。该对象为无参无返回值的函数对象即可。stl中提供了function对象。(在最初的版本中是自己实现函数对象的)


       /**

	*   @brief 在事务中执行处理

	*	@param[in] fun	处理函数

	*/

	void OnTransaction(const std::function<void()>& fun) throw (HiDBException);

(三) 接口的使用案例


HiDB m_DB = new HiDB(HiDBType_MySQL,  true);

try

{

    bool ret = m_DB->Open(

		"host=127.0.0.1;port=3306;dbname=test;user=root;pwd=root;charset=gbk;"

		);

    m_DB->ExecuteNoQuery("drop table if exists table1;");

    string val = m_DB->ExecuteScalar(

		"SELECT column4 FROM table1 WHERE column1=‘%s‘ AND column3=%d",

		&val, "hitest", 59);

    shared_ptr<HiDBTable> table = this->m_DB->ExecuteQuery(

		"SELECT * FROM table1 WHERE column1=‘%s‘ OR column1=‘%s‘",		

		"hitest", "mytest");

}

catch(HiDBException& e)

{

     // ...

}

(四) 其他

其实,我以前提供的接口比现在要复杂很多,首先我模仿ADO.NET,对SQL参数进行了封装,封装了SQL参数的名称,类型,是否为空,值等信息,对获得的数据也进行了类似的封装。 ,还针对SQL参数提供了Create和Delete函数。

有一个同时看了我的接口后说,我的接口太复杂了,分层不是明确。我接受了他的建议,就将接口修改为现在的接口了。

另外,执行事务接口,最开始我是自己创建函数对象的,这也增加了复杂度,后来使用了stl的function对象,辅以lambda表达式,则使用起来简单多了。

(五) 完整的接口:

<1>HiDBCommon.h 提供接口应用到的相关枚举和结构体


#pragma once



/**

*    @defgroup 数据库模块

* @{

*/ 

#include "HiDBExport.h"



#include <string>

#include <vector>

#include <map>

#include <sstream>



/** @brief 数据库类型 */

enum HiDBType

{

	HiDBType_Invail,	/**<  无效类型 */

	HiDBType_MySQL,	/**<  MySQL */

};



#ifndef HiDBTable



typedef std::map<std::string, std::string> HiDBMap;



/** @brief 查询结果 */

typedef std::vector<HiDBMap> HiDBTable; /**<  查询结果 */

#endif



/** @brief 数据库操作异常 */

class HI_DB_EXPORT HiDBException

{

public:

	HiDBException();

public:

	std::string ToSrting();

public:

	std::string		m_sql;			/**<  本次操作的SQL语句 */

	std::string		m_descript;		/**<  异常描述 */

	std::string		m_position;		/**<  异常位置 */

	long			m_errorId;		/**<  异常编号 */

	HiDBType		m_dbTyp;		/**<  数据库类型 */

};



/** @brief 异常语句宏 */

#define HiDBHelperOnError(ps, script,sql, id) \

	HiDBException exception;\

	exception.m_position = ps;\

	exception.m_descript = script;\

	exception.m_sql = sql;\

	exception.m_errorId = id;\

	throw exception;\

	//return false;



/**//** @}*/ // 数据库模块

<2> HiDB.h 主要的接口:


#pragma once



/**

*    @defgroup 数据库模块

* @{

*/ 



#include <memory>

#include <functional>



#include "HiDBCommon.h"



class HiDBImpl;



#pragma warning (disable: 4290)



/**

* @brief 数据库操作类,封装数据库的通用操作,本类使用策略模式实现

*	 @author  徐敏荣

*    @date    2012-06-14

*

* @par 修订历史

*    @version v0.5 \n

*	 @author  徐敏荣

*    @date    2012-06-14

*    @li 初始版本

*    @version v0.6 \n

*	 @author  徐敏荣

*    @date    2014-08-04

*    @li 简化程序

*

*/

class HI_DB_EXPORT  HiDB

{

public:



	/**

	*   @brief 构造函数

	*	@param[in] type			数据库类型

	*	@param[in] isUsingLock	是否需要使用互斥锁

	*/

	HiDB(HiDBType type = HiDBType_MySQL, bool isUsingLock = false);



	/**

	*   @brief 析构函数

	*/

	~HiDB();



public:

	

	/**

	*   @brief 打开数据库连接

	*	@param[in] conn			数据库连接字符串

	*   @retval true:成功,false;失败

	*   @par 实例:

	*   @code

	*	HiDB db;

	*	if (db.Open("host=127.0.0.1;port=3306;dbname=test;user=root;pwd=root;charset=gbk;"))

	*	{

	*		// 打开成功

	*	}

	*	else

	*	{

	*		// 打开失败

	*	}

	*   @endcode

	*/

	bool Open(const char* conn) throw (HiDBException);

	

	/**

	*   @brief 关闭据库连接

	*/

	void Close(void);

	

	/**

	*   @brief 数据库连接是否打开

	*/

	bool IsOpen();



public:

	

	/**

	*   @brief 执行SQL语句,并不返回结果

	*	@param[in] conn			SQL语句

	*   @retval true:成功,false;失败

	*   @par 实例:

	*   @code

	*	HiDB db;

	*	if (db.ExecuteNoQuery("UPDATE table SET Paramer1=‘%s‘ 

	*		and Paramer2=‘%s‘ OR Paramer3=%d", "test1", "test2", 3))

	*	{

	*		// 执行成功

	*	}

	*	else

	*	{

	*		// 执行失败

	*	}

	*   @endcode

	*/

	bool ExecuteNoQuery(const char* sql, ...) throw (HiDBException);

	

public:



	/**

	*   @brief 执行SQL语句,返回一个结果

	*	@param[in] sql			SQL语句

	*   @retval 获得的数据,如果为空,则失败

	*/

	std::string ExecuteScalar(const char* sql, ...) throw (HiDBException);

	

public:



	/**

	*   @brief 执行SQL语句,返回一个结果集合

	*	@param[in] sql			SQL语句

	*   @retval 存储查询记录的智能指针

	*/

	std::shared_ptr<HiDBTable> ExecuteQuery(const char* sql, ...) throw (HiDBException);

	

public:	



	/**

	*   @brief 在事务中执行处理

	*	@param[in] fun	处理函数

	*/

	void OnTransaction(const std::function<void()>& fun) throw (HiDBException);



private:

	/**

	*   @brief 数据库操作实现指针

	*/

	HiDBImpl*	m_Impl;		/**< 数据库操作实现指针 */

};



/**//** @}*/ // 数据库模块

三 实现

实现采用了从《Effective C++》中学习到的实现与接口相分析的原则,在HiDB中使用HiDBImpl实现访问数据库的逻辑。

(一) 可变参数的处理

当然,在HiDB中是需要解决根据sql参数和可变参数拼装成一个完整SQL语句的问题。

该问题使用一个宏来实现:


#if !defined(HISDB_ON_VARLIST)

#define HISDB_ON_VARLIST(x, y) \

	char chArr[2048] = {0};\

	char* pchar = &chArr[0];\

	va_list pArgList;\

	va_start(pArgList, y);\

	::_vsnprintf(chArr, 2047, x, pArgList);	\

	va_end(pArgList) ;

#endif

(二) 互斥锁的实现

自己根据临界区,实现了一个互斥锁,互斥锁接口如下:

1: 构造函数: 实现临界区的初始化

2: 析构函数: 实现临界区的删除

3: 进入临界区

4: 离开临界区

实现函数如下:


/**

* @brief 临界区访问类,主要封装windows临界区的访问,该类主要在栈中使用,利用局部变量的构造和析构函数出入临界区

*	 @author  徐敏荣

*    @date    2012-06-14

*

* @par 修订历史

*    @version v0.5 \n

*	 @author  徐敏荣

*    @date    2012-06-14

*    @li 初始版本

*

*/

class HiCritical

{

public:



	/**

	*   @brief 构造函数

	*/

	HiCritical()

	{

		::InitializeCriticalSection(&cs);

	}



	/**

	*   @brief 析构函数

	*/

	~HiCritical()

	{

		::DeleteCriticalSection(&cs);

	}



	/**

	*   @brief 进入临界区

	*/

	void Enter()

	{

		::EnterCriticalSection(&cs);

	}

	

	/**

	*   @brief 离开临界区

	*/

	void Leave()

	{

		::LeaveCriticalSection(&cs);

	}



	CRITICAL_SECTION* GetSection()

	{

		return &cs;

	}

private:

	

	/**

	*   @brief 临界区对象

	*/

	CRITICAL_SECTION	cs;			/**< 临界区对象 */

};

另外还提供一个临界区管理类(HiCriticalMng),在构造该类时,进入临界区,析构该类时离开临界区。如果构造函数中传入的是NULL,则不进行任何互斥处理。




/**

* @brief 临界区访问管理类,利用构造函数进入临界区,利用西沟函数离开临界区

*		如果向构造函数提供NULL参数,则不使用临界区。

*

*/

class HiCriticalMng

{

public:

	HiCriticalMng(HiCritical& crl): cl(&crl)

	{

		cl->Enter();

	}



	HiCriticalMng(HiCritical* crl): cl(crl)

	{

		if (cl)

		{

			cl->Enter();

		}

	}



	~HiCriticalMng()

	{

		if (cl)

		{

			cl->Leave();

		}

	}



private:

	HiCritical*   cl;

};

(三) HiDBImpl的接口

作为数据库访问类,HiDBImpl实现HiDB需要的所有接口,所以HiDBImpl与HiDB接口类似,但是HiDBImpl接口接收的参数为完整的SQL语句(因为带可变参数的SQL语句已经被HiDB处理了)。

HiDBImpl不但要支持MySQL,以后还要支持其他数据库,所以不能有LibMySQL相关的东西,HiDBImpl应该是一个基类,可以被派生,例如派生出支持LibMySQL的子类。

HiDBImpl要线程安全的,所以要包含互斥锁HiCritical,又要可以非线程安全(HiCriticalMng支持NULL参数),所以HiCritical需要时这指针,这样,HiDBImpl的接口就出来了。

HiDBImpl接口如下:




#pragma once

/**

*    @defgroup 数据库操作实现类接口类

*    @brief    数据库操作实现类接口类,声明数据库操作实现类的接口。

*	 @author  徐敏荣

*    @date    2012-06-14

*

* @par 修订历史

*    @version v0.5 \n

*	 @author  徐敏荣

*    @date    2012-06-14

*    @li 初始版本

* @{

*/ 



#include "DB/HiDB.h"

class HiCritical;

/**

* @brief 数据库操作实现类接口类,声明数据库操作实现类的接口

*

*/

class  HiDBImpl

{

public:



	/**

	*   @brief 构造函数

	*	@param[in] isUsingLock	是否需要使用互斥锁

	*/

	HiDBImpl(bool isUsingLock);



	/**

	*   @brief 析构函数

	*/

	virtual ~HiDBImpl();



public:

		

	/**

	*   @brief 打开数据库连接

	*	@param[in] conn			数据库连接字符串

	*   @retval true:成功,false;失败

	*/

	virtual bool Open(const char* conn) = 0;

		

	/**

	*   @brief 关闭据库连接

	*/

	virtual void Close(void) = 0;



public:

		

	/**

	*   @brief 执行SQL语句,并不返回结果

	*	@param[in] conn			SQL语句

	*   @retval true:成功,false;失败

	*/

	virtual bool ExecuteNoQuery(const char* sql) = 0;



public:



	/**

	*   @brief 执行SQL语句,返回一个结果

	*	@param[in] sql			SQL语句

	*	@param[out] value		取得的结果

	*   @retval true:成功,false;失败

	*/

	virtual std::string ExecuteScalar(const char* sql) = 0;

public:



	/**

	*   @brief 执行SQL语句,返回一个结果集合

	*	@param[in] sql			SQL语句

	*	@param[out] table		取得的结果集合

	*   @retval true:成功,false;失败

	*/

	virtual std::shared_ptr<HiDBTable> ExecuteQuery(const char* sql) = 0;



public:	

		

	/**

	*   @brief 事物处理

	*   @retval true:成功,false;失败

	*/

	virtual void OnTransaction(const std::function<void()>& fun) = 0;





protected:



	/**

	*   @brief 临界区对象,为空表示不需要考虑资源并发访问

	*/

	HiCritical*	m_pCritical;

};



/**//** @}*/ // 数据库操作实现类接口类

(四)HiDB的实现:

由HiDB负责实现可变参数转换为完整SQL语句,HiDBImpl负责实现所有数据库访问逻辑,并要为以后添加其他数据库支持这些需求可以推到出HiDB的实现代码:


#include <stdarg.h>

#include "DB/HiDB.h"

#include "HiDBMySQL.h"



using namespace std;



#if !defined(HISDB_ON_VARLIST)

#define HISDB_ON_VARLIST(x, y) \

	char chArr[2048] = {0};\

	char* pchar = &chArr[0];\

	va_list pArgList;\

	va_start(pArgList, y);\

	::_vsnprintf(chArr, 2047, x, pArgList);	\

	va_end(pArgList) ;

#endif





static bool IsImplOK(HiDBImpl* db)

{

	if (!db)

	{

		return false;

	}

	/*

	if (!db->IsOpen())

	{

		return false;

	}*/

	return true;

}



// 构造函数

HiDB::HiDB(HiDBType type, bool isUsingLock):m_Impl(NULL)

{

	if (type == HiDBType_MySQL)

	{

		this->m_Impl = new HiDBMySQL(isUsingLock);

	}

}



// 析构函数

HiDB::~HiDB()

{

	if (this->m_Impl)

	{

		delete this->m_Impl;

		this->m_Impl = NULL;

	}

}



// 打开数据库连接

bool HiDB::Open(const char* conn)

{

	if (!this->m_Impl)

	{

		return false;

	}



	return this->m_Impl->Open(conn);

}



bool HiDB::IsOpen()

{

	if (!this->m_Impl)

	{

		return false;

	}



	return true;//this->m_Impl->IsOpen();

}



void HiDB::Close(void)

{

	if (!IsImplOK(this->m_Impl))

	{

		return;

	}



	return this->m_Impl->Close();

}



bool HiDB::ExecuteNoQuery(const char* sql, ...)

{

	if (!IsImplOK(this->m_Impl))

	{

		return false;

	}



	HISDB_ON_VARLIST(sql, sql);



	return this->m_Impl->ExecuteNoQuery(chArr);

}



string HiDB::ExecuteScalar(const char* sql, ...)

{

	if (!IsImplOK(this->m_Impl))

	{

		return "";

	}



	HISDB_ON_VARLIST(sql, sql);

	

	return this->m_Impl->ExecuteScalar(chArr);

}



std::shared_ptr<HiDBTable> HiDB::ExecuteQuery(const char* sql, ...)

{

	if (!IsImplOK(this->m_Impl))

	{

		return NULL;

	}

	HISDB_ON_VARLIST(sql, sql);



	return this->m_Impl->ExecuteQuery(chArr);

}	



void HiDB::OnTransaction(const std::function<void()>& fun)

{

	if (!IsImplOK(this->m_Impl))

	{

		HiDBHelperOnError("HiDB::OnTransaction", 

			"HiDB is not impl", "", 0);

	}

	return this->m_Impl->OnTransaction(fun);

}

四 后记

至此,HiDB所有主要的接口和主要的实现就介绍的差不多,其他更多的实现,可以参照源码自己实现。类图将在本文后面提供。

后续的工作包括对HiDB进行测试,我期望能进行自动化测试,类似于Junit。但是我并不知道C++有哪些自动化测试工具,没办法,只有自己写C++自动化测试工具来测试HiDB了,后面的文章我打算介绍一下我写的一个C++自动化测试工具。

HiDB类图:

源代码:http://download.csdn.net/detail/xumingxsh/7778417

我的C++数据库访问类

时间: 2024-10-24 22:41:31

我的C++数据库访问类的相关文章

一个C#的XML数据库访问类

原文地址:http://hankjin.blog.163.com/blog/static/33731937200942915452244/ 程序中不可避免的要用到配置文件或数据,对于数据量比较小的程序,部署数据库花费的时间就显得浪费了,因此用XML来存储不妨为一个很好的办法,而且结合C#的DataSet,我们可以很轻易的封装出一个代码简单而功能强大的数据访问类XMLConfigconfig.xml<root>  <table1>    <rowName1>hello&l

Sqlite 数据库访问类

使用Sqlite 作为软件数据库: 实现了数据库访问类 C#  使用System.Data.Sqlite 下载地址: http://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki网站中下载Precompiled Statically-Linked Binaries for 32-bit Windows (.NET Framework 4.5)或者Precompiled Statically-Linked Binarie

ADO数据库访问类查询、属性扩展

1 数据库访问类查询 (1)查询一条 有参数:查询这条信息的主键: 有返回值:返回值是一个实体类: dr.read();执行一遍,读取这行信息并放进users类型中. ///返回users实体类类型 public users chayi(string name) { users u = null; com.CommandText = "select *from users where [email protected]"; com.Parameters.Clear(); com.Par

Java知多少(111)几个重要的java数据库访问类和接口

修改数据表记录也有3种方案. 一.使用Statement对象 实现修改数据表记录的SQL语句的语法是:    update表名 set 字段名1 = 字段值1,字段名2 = 字段值2,……where特定条件例如: update ksInfo set 姓名 = ‘张小卫’where 姓名 = ‘张大卫’ 先创建一个SQL语句,然砶调用Statement对象的executeUpdate()方法.例如, 1 sql = “update ksInfo set 姓名 = ‘”+txtName.getTex

学习实践:使用模式,原则实现一个C++数据库访问类

一.概述 在我参与的多个项目中,大家使用libMySQL操作MySQL数据库,而且是源码即复用,在多个项目中有多套相同或相似的源码,这样的复用方式给开发带来了不变,而且libMySQL的使用比较麻烦,要应对很多的细节,很容易出错. 我要写一个动态链接库,将对libMySQL的操作封装起来,以二进制复用代替源码级复用:要提供线程安全的接口,用户无需关系是否加锁这样细节性的问题,减少出错及死锁的机会,当然也要允许用户自己选择是否线程安全的访问数据库:要简化访问数据库的流程,接口越简单越好. 我从20

DataAccess通用数据库访问类,简单易用,功能强悍

以下是我编写的DataAccess通用数据库访问类,简单易用,支持:内联式创建多个参数.支持多事务提交.支持参数复用.支持更换数据库类型,希望能帮到大家,若需支持查出来后转换成实体,可以自行扩展datarow转实体类,也可以搭配dapper.net实现更强大的功能. /// <summary> /// 通用数据库访问类,支持多种数据库,无直接依赖某个数据库组件 /// 作者:左文俊 /// 日期:2016-6-3 /// </summary> public class DataAc

抽离CodeIgniter的数据库访问类 可以独立使用

好吧,因为组织需要,最近又开始转战php了,业务逻辑都还好说,主要是老大要求在数据访问层上加上登录态验证.其实这种要求也是合理的,互联网服务要求上层保护下层,但下层不能完全相信上层.但是问题也就来了,有如下两种方案:1.写一个mysql proxy server,用来将调用方发来的请求拼装,然后返回给调用侧.这样做的主要难度在于:a)SQL语句的拼装及序列化b)数据集序列化,虽然有不少这方面的产品,但是终究还是太过复杂,而且没有时间折腾果断放弃.2.封装一层mysql的api,调用方直接在本地调

我也来写:数据库访问类DBHelper

一.前言 相信许多人都百度过:“.net 数据库访问类”.然后就出来一大堆SqlHelper.我也用过这些SqlHelper,也自己写过,一堆静态方法,开始使用起来感觉很不错,它们也确实在很多时候可以很好的工作.ADO.NET已经封装很好了,我们很容易就可以实现自己的数据库访问类. 很久前,忘记在哪里看到过了,有一个朋友写了一篇[如何做一个好用的数据库访问类](有兴趣的朋友仍然可以搜索到),这篇文章确实写得很好,作者很详细的讲解了如何设计一个好的数据库访问类:所谓“好“是指:轻量.易用.通用.高

我也来写:数据库访问类DBHelper(转)

一.前言 相信许多人都百度过:“.net 数据库访问类”.然后就出来一大堆SqlHelper.我也用过这些SqlHelper,也自己写过,一堆静态方法,开始使用起来感觉很不错,它们也确实在很多时候可以很好的工作.ADO.NET已经封装很好了,我们很容易就可以实现自己的数据库访问类. 很久前,忘记在哪里看到过了,有一个朋友写了一篇[如何做一个好用的数据库访问类](有兴趣的朋友仍然可以搜索到),这篇文章确实写得很好,作者很详细的讲解了如何设计一个好的数据库访问类:所谓“好“是指:轻量.易用.通用.高