使用Mysqlpp
本文最后更新于:February 26, 2022 pm
Recent projects require using mysqlpp as a C++<->mysql middleware.
This blog records basic usage and advice on using the library.
Most words are extracted from official docs and reference link is left at the end of this blog.
Considering limited time, translating to Chinese is temporarily put on hold.
connection
Like other library, you need to get a connection from your platform to db server first.
Connection obj derives from OptionalException
query
query object, stream support provided
template queries, which means prepared sql statement
ssqls, C++structure <–> sql schemas , orm mechanism
result set
- field data stored in class
String
likestd::string
, conversion operators provided to any C type; - MySQL++ provides with classes like DateTime, to be initialized from a MySQL DATETIME string.
- custom behavior when bad conversions occurs: throw exceptions or set a warning flag
queries that don’t return data
queries like create table ...;
, update ...
don’t pull data from tables;
an instance of class SimpleResult
is given to signal if the operation is successful as well as number of rows impacted(if any)
return MySQL++ Data Structures
use Query::store()
to return an object of StoreQueryResult
, which derives from std::vector<mysqlpp:Row>
, of course with random access support.
each Row
obj is also like a vector——std::vector<String>
, each String
corresponds with one field data.
operation:
result[1][4]
(all indexes start from 0)
result[1]["price"]
(access a field by field name)
Specialized SQL structures
with ssqls:
1 |
|
no ssqls but after mysql++ v3
use Row
directly
1 |
|
exceptions
library throws exceptions whenever an error occurs.
You can config library to set error flag instead, but exceptions will carry more information
the lib may trigger many kind of exceptions, all distinguishable with a single try
block
classDiagram
std_exception <|--Exception
Exception<|--library_exception
when exceptions suppressed, return either an error code or an obj (test as false), or have the obj’s error flag set.
disable exceptions on a connection means everything flows on it should not throw any exceptions
passing false to the constructor of a connection obj
it’s possible to have exceptions most of the time but suppress them in some code blocks.
to do that, create a code block to encapsulate your code and create an instance of NoExceptions
which take OptionalExceptions
derivatives. The obj will store error flag and when it’s destroyed, it restores throwing exception mode.
1 |
|
cases where exceptions are thrown unconditionlly:
- index out of bound(Row[$+\infty$])
BadIndex
、 no such field Row[“no_such_field”]BadFieldName
, these are situations after mysql++ 3.0.7; in the paststd::range_error
String
will throwBadConversioin
if conversion is improper. 1.23 to int ×, 1.00 to int √- template queries with insufficient parameters
BadParamCount
- a C++ type that mysqlpp doesn’t know how to convert to sql.
TypeLookupFailed
Quoting and Escaping
you need to tell mysqlpp explicitly when additional quoting and escaping are necessary.
1 |
|
–>
1 |
|
quote_only add a single quotes pairs to the next thing inserted to the stream.
escape is provided too, with the same mechanism
most widely used:
quote = escape + quote_only
1 |
|
->
1 |
|
types
db only stores numbers and text strings.
things travel between your app and db are only strings. including sql language
after v3.0.2, no data loss in sql float and double reported, but data loss in sql decimal type still exists
lib/sql_types.h
defines data types that are compatible with sql.
Those types starts with sql_
, in the middle are "\_".join(sql_type_name.split(" "))
, if with _null
at tail, it means this type is compatible with sql null value
you can also use C++ types instead, like int
vs mysql::sql_tinyint_unsigned
advantages with mysql++ type:
- space efficiency
- portability and cross platfrom
- clarity
- compatibility
no exotic data types provided yet, like geospatial types
sql null
modifier
null in sql is a modifier to allow you store null value to the column while nothing like it exists in C++
null support is a template in mysqlpp
1 |
|
unique value
mysqlpp provide global null obj to represent sql null value.
1 |
|
special string
SQLTypeAdapter
convert given data to sql_string, mostly used by class String
, users don’t use it often
String
represents a sql string, with a bunch of type conversion functions overloaded.
Binary types
currently not concerned
Transactions
create a Transaction object at the start of your code block,
when everything you finished, you call obj.commit()
if the object is destroyed before you call commit()
( out of scope or exception thrown ), it rolls back automatically
mysql server kills deadlock by rollback the second transaction.
exception_instance.errnum()
-> ER_LOCK_DEADLOCK
Query type
Query::execute()
for queries that don’t pull out data but only receives execution result: like create table
Query::store()
: for queries that give the result in smaller memory scale. it receives all results and store all of them on the machine your app is running on, please consider the run time memory cost when the result set gets larger.
Query::storein(std containers)
: put the result into the container, but the container must be instantiated with ssqls type.
Query::user()
: tell sql server to return the results one line each time to be processed linearly
1 |
|
Sometimes you need to pull some records out of sql server and filter them in C++
Query::use_if()
1 |
|
Template Query
example:
1 |
|
parameter form:
1 |
|
modifer | Description |
---|---|
% | Print an actual “%” |
“” | Don’t quote or escape no matter what. |
q | This will escape the item using the MySQL C API function mysql_escape_string() and add single quotes around it as necessary, depending on the type of the value you use. |
Q | Quote but don’t escape based on the same rules as for “q”. This can save a bit of processing time if you know the strings will never need quoting |
at run time:
1 |
|
–>
1 |
|
set default params
set default params of template query
1 |
|
if you keep fields less likely to change and set its default value:
1 |
|
—>
no need to pass them all the time
1 |
|
Specialized SQL Structures
This feature let’s you define a C++ structure that matches the from of your sql table.
But it gives more than column-member var mapping.
To define such a structure, you must use a macron in ssqls.h
sql_create
suppose a sql scheme is like:
1 |
|
you can create a cpp structure like this
1 |
|
this declares a data strucure stock
in C++, which has a data member for each SQL column, with the same names.
The structure also has many member functions, operators and hidden data members.
general form of macron
1 |
|
here #
after sql_create_ is the number of all data members.
compcount and setcount will be introduced in the coming paragraphs.
ssqls comparison and initialization
compcount=xxx
means when 2 ssqls are compared, the first xxx fields will be compared, must be larger than 0;
setcount=yyy
means when yyy is given >=0, the macron will additionally add a set()member function and a constructor which both take yyy parameters and set those parameters to the first yyy field.
note:
compcount and setcount can’t be equal, because compcount will gen a constructor that takes comcount params.
retrieve data
1 |
|
you can also define a subset of the schema, it’s ok.
Even a superset is also acceptable.
1 |
|
add data
insert a single row
the insert method will take care of quoting and escaping automatically.
1 |
|
insert many rows
1 |
|
you can chain Query
operations like in the last line above, because its methods return *this
where that makes sense.
modify data
1 |
|
use an ssqls in mutiple modules
if you extract the definition to a header file and include it wherever you need this structure, you will get a link error because the structure has static members to store meta info, such as table name and the list of the field names.
solution:
define preprocessor macron MYSQLPP_SSQLS_NO_STATICS
in all file you need but one that owns the structure.
Connection Pool
when programming multithreadedly in a relatively smaller thread number scale, and each thread is accessing the db frequent enough, just let each thread have its own connection.
when 2 many threads are asking for connection or threads rarely access the db, connection pools are supposed to be used.
mysqlpp provides an interface of ConnectionPool
, to instantiate it , one needs to overload 3 functions:
create()
: create a conn with host, username, pswd …destroy()
: destroy a connection obj, since the superclass don’t know if the obj is allocated by new or on run time stackmax_idle_time()
: configure max idle time
Make the connection pool singleton.
To make getting a connection RAII, use mysqlpp::ScopedConnection(*Connection, bool)
when a thread need a connection, which will point to the real connection obj.
Reference
4. Template Queries (tangentsoft.com)
5. Specialized SQL Structures (tangentsoft.com)
7. Using MySQL++ in a Multithreaded Program (tangentsoft.com)
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!