The database can be operated asynchronously through asio.
6 files modified
1 files added
| | |
| | | |
| | | ``` |
| | | Database connections are usually not thread-safe. User code should guarantee that a connection can only be used by one thread at a time. |
| | | For use this feature, GCC requires version 5 or higher. |
| | | |
| | | ## About MySQL |
| | | |
| | |
| | | |
| | | ``` |
| | | 数据库连接通常不是线程安全的。用户代码应该保证,一个连接只能同时由一个线程使用。 |
| | | 使用这项功能,GCC需要 5 或更高版本才行。 |
| | | |
| | | ## 有关MySQL的说明 |
| | | |
| New file |
| | |
| | | #ifndef _QTL_ASIO_H_ |
| | | #define _QTL_ASIO_H_ |
| | | |
| | | #include <qtl_async.hpp> |
| | | #include <asio/version.hpp> |
| | | #define ASIO_STANDALONE |
| | | #if ASIO_VERSION < 101200 |
| | | #include <asio/io_service.hpp> |
| | | #else |
| | | #include <asio/io_context.hpp> |
| | | #endif // ASIO_VERSION |
| | | #include <asio/strand.hpp> |
| | | #include <asio/ip/tcp.hpp> |
| | | #include <asio/async_result.hpp> |
| | | #include <asio/steady_timer.hpp> |
| | | |
| | | #if ASIO_VERSION < 100000 |
| | | #error The asio version required by QTL is at least 10.0 |
| | | #endif |
| | | |
| | | namespace qtl |
| | | { |
| | | |
| | | namespace NS_ASIO = ::asio; |
| | | |
| | | namespace asio |
| | | { |
| | | |
| | | class service |
| | | { |
| | | public: |
| | | #if ASIO_VERSION < 101200 |
| | | typedef NS_ASIO::io_service service_type; |
| | | #else |
| | | typedef NS_ASIO::io_context service_type; |
| | | #endif // ASIO_VERSION |
| | | |
| | | service() { } |
| | | explicit service(int concurrency_hint) : _service(concurrency_hint) { } |
| | | |
| | | void reset() |
| | | { |
| | | _service.reset(); |
| | | } |
| | | |
| | | void run() |
| | | { |
| | | _service.run(); |
| | | } |
| | | |
| | | void stop() |
| | | { |
| | | _service.stop(); |
| | | } |
| | | |
| | | service_type& context() { return _service; } |
| | | |
| | | private: |
| | | |
| | | class event_item : public qtl::event |
| | | { |
| | | public: |
| | | event_item(service_type& service, qtl::socket_type fd) |
| | | : _strand(service), _socket(service, NS_ASIO::ip::tcp::v4(), fd), _timer(service), _busying(false) |
| | | { |
| | | } |
| | | |
| | | NS_ASIO::ip::tcp::socket& next_layer() { return _socket; } |
| | | |
| | | public: // qtl::event |
| | | virtual void set_io_handler(int flags, long timeout, std::function<void(int)>&& handler) override |
| | | { |
| | | if (flags&qtl::event::ef_read) |
| | | { |
| | | #if ASIO_VERSION < 101200 |
| | | _socket.async_read_some(NS_ASIO::null_buffers(), _strand.wrap([this, handler](const NS_ASIO::error_code& ec, size_t bytes_transferred) { |
| | | #else |
| | | _socket.async_wait(NS_ASIO::socket_base::wait_read, _strand.wrap([this, handler](const NS_ASIO::error_code& ec) { |
| | | #endif // ASIO_VERSION |
| | | if (!ec) |
| | | handler(qtl::event::ef_read); |
| | | else if (ec == NS_ASIO::error::make_error_code(NS_ASIO::error::operation_aborted)) |
| | | handler(qtl::event::ef_timeout); |
| | | else |
| | | handler(qtl::event::ef_exception); |
| | | _busying = false; |
| | | })); |
| | | _busying = true; |
| | | } |
| | | if (flags&qtl::event::ef_write) |
| | | { |
| | | #if ASIO_VERSION < 101200 |
| | | _socket.async_write_some(NS_ASIO::null_buffers(), _strand.wrap([this, handler](const NS_ASIO::error_code& ec, size_t bytes_transferred) { |
| | | #else |
| | | _socket.async_wait(NS_ASIO::socket_base::wait_write, _strand.wrap([this, handler](const NS_ASIO::error_code& ec) { |
| | | #endif //ASIO_VERSION |
| | | if (!ec) |
| | | handler(qtl::event::ef_write); |
| | | else if (ec == NS_ASIO::error::make_error_code(NS_ASIO::error::operation_aborted)) |
| | | handler(qtl::event::ef_timeout); |
| | | else |
| | | handler(qtl::event::ef_exception); |
| | | _busying = false; |
| | | })); |
| | | _busying = true; |
| | | } |
| | | if (timeout > 0) |
| | | { |
| | | #if ASIO_VERSION < 101200 |
| | | _timer.expires_from_now(std::chrono::seconds(timeout)); |
| | | #else |
| | | _timer.expires_after(NS_ASIO::chrono::seconds(timeout)); |
| | | #endif // ASIO_VERSION |
| | | _timer.async_wait(_strand.wrap([this, handler](NS_ASIO::error_code ec) { |
| | | if (!ec) |
| | | { |
| | | _socket.cancel(ec); |
| | | } |
| | | })); |
| | | } |
| | | } |
| | | |
| | | virtual void remove() override |
| | | { |
| | | #if ASIO_VERSION < 101200 && (!defined(_WIN32) && _WIN32_WINNT >= 0x0603 ) |
| | | _socket.release(); |
| | | #endif //Windows 8.1 |
| | | } |
| | | virtual bool is_busying() override |
| | | { |
| | | return _busying; |
| | | } |
| | | |
| | | private: |
| | | service_type::strand _strand; |
| | | NS_ASIO::ip::tcp::socket _socket; |
| | | NS_ASIO::steady_timer _timer; |
| | | bool _busying; |
| | | }; |
| | | |
| | | public: |
| | | |
| | | template<typename Connection> |
| | | event_item* add(Connection* connection) |
| | | { |
| | | event_item* item = new event_item(_service, connection->socket()); |
| | | _events.push_back(std::unique_ptr<event_item>(item)); |
| | | return item; |
| | | } |
| | | |
| | | private: |
| | | service_type _service; |
| | | std::vector<std::unique_ptr<event_item>> _events; |
| | | }; |
| | | |
| | | #if ASIO_VERSION < 101200 |
| | | |
| | | template <typename Handler, typename Signature> |
| | | using async_init_type = NS_ASIO::detail::async_result_init<Handler, Signature>; |
| | | |
| | | template <typename Handler, typename Signature> |
| | | inline typename NS_ASIO::handler_type<Handler, Signature>::type |
| | | get_async_handler(async_init_type<Handler, Signature>& init) |
| | | { |
| | | return init.handler; |
| | | } |
| | | |
| | | #else |
| | | |
| | | template <typename Handler, typename Signature> |
| | | using async_init_type = NS_ASIO::async_completion<Handler, Signature>; |
| | | |
| | | template <typename Handler, typename Signature> |
| | | inline typename async_init_type<Handler, Signature>::completion_handler_type |
| | | get_async_handler(async_init_type<Handler, Signature>& init) |
| | | { |
| | | return init.completion_handler; |
| | | } |
| | | |
| | | #endif // ASIO_VERSION |
| | | |
| | | template<typename Connection, typename OpenHandler, typename... Args> |
| | | inline ASIO_INITFN_RESULT_TYPE(OpenHandler, void(typename Connection::exception_type)) |
| | | async_open(service& service, Connection& db, OpenHandler&& handler, Args&&... args) |
| | | { |
| | | async_init_type<OpenHandler, |
| | | void(typename Connection::exception_type)> init(std::forward<OpenHandler>(handler)); |
| | | db.open(service, get_async_handler(init), std::forward<Args>(args)...); |
| | | return init.result.get(); |
| | | } |
| | | |
| | | template<typename Connection, typename CloseHandler, typename... Args> |
| | | inline ASIO_INITFN_RESULT_TYPE(CloseHandler, void()) |
| | | async_close(Connection& db, CloseHandler&& handler, Args&&... args) |
| | | { |
| | | async_init_type<CloseHandler, |
| | | void()> init(std::forward<CloseHandler>(handler)); |
| | | db.close(get_async_handler(init), std::forward<Args>(args)...); |
| | | return init.result.get(); |
| | | } |
| | | |
| | | template<typename Connection, typename ExecuteHandler, typename... Args> |
| | | inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t)) |
| | | async_execute(Connection& db, ExecuteHandler&& handler, Args&&... args) |
| | | { |
| | | async_init_type<ExecuteHandler, |
| | | void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler)); |
| | | db.execute(get_async_handler(init), std::forward<Args>(args)...); |
| | | return init.result.get(); |
| | | } |
| | | |
| | | template<typename Connection, typename ExecuteHandler, typename... Args> |
| | | inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t)) |
| | | async_execute_direct(Connection& db, ExecuteHandler&& handler, Args&&... args) |
| | | { |
| | | async_init_type<ExecuteHandler, |
| | | void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler)); |
| | | db.execute_direct(get_async_handler(init), std::forward<Args>(args)...); |
| | | return init.result.get(); |
| | | } |
| | | |
| | | template<typename Connection, typename ExecuteHandler, typename... Args> |
| | | inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t)) |
| | | async_insert(Connection& db, ExecuteHandler&& handler, Args&&... args) |
| | | { |
| | | async_init_type<ExecuteHandler, |
| | | void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler)); |
| | | db.insert(get_async_handler(init), std::forward<Args>(args)...); |
| | | return init.result.get(); |
| | | } |
| | | |
| | | template<typename Connection, typename ExecuteHandler, typename... Args> |
| | | inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t)) |
| | | async_insert_direct(Connection& db, ExecuteHandler&& handler, Args&&... args) |
| | | { |
| | | async_init_type<ExecuteHandler, |
| | | void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler)); |
| | | db.insert_direct(get_async_handler(init), std::forward<Args>(args)...); |
| | | return init.result.get(); |
| | | } |
| | | |
| | | template<typename Connection, typename FinishHandler, typename... Args> |
| | | inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type)) |
| | | async_query(Connection& db, FinishHandler&& handler, Args&&... args) |
| | | { |
| | | async_init_type<FinishHandler, |
| | | void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler)); |
| | | db.query(std::forward<Args>(args)..., get_async_handler(init)); |
| | | return init.result.get(); |
| | | } |
| | | |
| | | template<typename Connection, typename FinishHandler, typename... Args> |
| | | inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type)) |
| | | async_query_explicit(Connection& db, FinishHandler&& handler, Args&&... args) |
| | | { |
| | | async_init_type<FinishHandler, |
| | | void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler)); |
| | | db.query_explicit(std::forward<Args>(args)..., get_async_handler(init)); |
| | | return init.result.get(); |
| | | } |
| | | |
| | | template<typename Connection, typename A1, typename A2, typename FinishHandler, typename... RowHandlers> |
| | | inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type)) |
| | | async_query_multi_with_params(Connection& db, A1&& a1, A2&& a2, FinishHandler&& handler, RowHandlers&&... row_handlers) |
| | | { |
| | | async_init_type<FinishHandler, |
| | | void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler)); |
| | | db.query_multi_with_params(std::forward<A1>(a1), std::forward<A2>(a2), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...); |
| | | return init.result.get(); |
| | | } |
| | | |
| | | template<typename Connection, typename A1, typename FinishHandler, typename... RowHandlers> |
| | | inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type)) |
| | | async_query_multi_with_params(Connection& db, A1&& a1, FinishHandler&& handler, RowHandlers&&... row_handlers) |
| | | { |
| | | async_init_type<FinishHandler, |
| | | void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler)); |
| | | db.query_multi_with_params(std::forward<A1>(a1), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...); |
| | | return init.result.get(); |
| | | } |
| | | |
| | | template<typename Connection, typename A1, typename A2, typename FinishHandler, typename... RowHandlers> |
| | | inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type)) |
| | | async_query_multi(Connection& db, A1&& a1, A2&& a2, FinishHandler&& handler, RowHandlers&&... row_handlers) |
| | | { |
| | | async_init_type<FinishHandler, |
| | | void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler)); |
| | | db.query_multi(std::forward<A1>(a1), std::forward<A2>(a2), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...); |
| | | return init.result.get(); |
| | | } |
| | | |
| | | template<typename Connection, typename A1, typename FinishHandler, typename... RowHandlers> |
| | | inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type)) |
| | | async_query_multi(Connection& db, A1&& a1, FinishHandler&& handler, RowHandlers&&... row_handlers) |
| | | { |
| | | async_init_type<FinishHandler, |
| | | void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler)); |
| | | db.query_multi(std::forward<A1>(a1), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...); |
| | | return init.result.get(); |
| | | } |
| | | |
| | | } |
| | | |
| | | } |
| | | |
| | | #endif //_QTL_ASIO_H_ |
| | |
| | | void test_alive() |
| | | { |
| | | if (m_connections.empty()) |
| | | return false; |
| | | return; |
| | | std::unique_lock<std::mutex> lock(m_pool_mutex); |
| | | auto it = m_connections.begin(); |
| | | while (it != m_connections.end()) |
| | |
| | | int status = mysql_close_start(m_mysql); |
| | | if (status) |
| | | { |
| | | wait_close(status, [this, handler]() { |
| | | wait_close(status, [this, handler]() mutable { |
| | | handler(); |
| | | m_mysql = nullptr; |
| | | }); |
| | |
| | | void wait_close(int status, CloseHandler&& handler) NOEXCEPT |
| | | { |
| | | m_event_handler->set_io_handler(event_flags(status), mysql_get_timeout_value(m_mysql), |
| | | [this, handler](int flags) { |
| | | [this, handler](int flags) mutable { |
| | | MYSQL* ret = nullptr; |
| | | int status = mysql_close_cont(m_mysql, mysql_status(flags)); |
| | | if (status) |
| | |
| | | void wait_query(int status, int field_count, RowHandler&& row_handler, ResultHandler&& result_handler) NOEXCEPT |
| | | { |
| | | m_event_handler->set_io_handler(event_flags(status), mysql_get_timeout_value(m_mysql), |
| | | [this, field_count, row_handler, result_handler](int flags) { |
| | | [this, field_count, row_handler, result_handler](int flags) mutable { |
| | | MYSQL_RES* result = 0; |
| | | int status = mysql_store_result_cont(&result, m_mysql, mysql_status(flags)); |
| | | if (status) |
| | |
| | | #include <time.h> |
| | | #include <limits.h> |
| | | #include "../include/qtl_mysql_pool.hpp" |
| | | #include "../include/qtl_asio.hpp" |
| | | |
| | | #if MARIADB_VERSION_ID < 0100000 |
| | | #error "The program need mariadb version > 10.0" |
| | | #endif |
| | | |
| | | class simple_event_loop |
| | | { |
| | | public: |
| | | simple_event_loop() |
| | | { |
| | | m_expired = 0; |
| | | m_maxfd = 0; |
| | | m_stoped = false; |
| | | FD_ZERO(&m_readset); |
| | | FD_ZERO(&m_writeset); |
| | | FD_ZERO(&m_exceptset); |
| | | } |
| | | |
| | | void reset() |
| | | { |
| | | m_stoped = false; |
| | | } |
| | | |
| | | void run() |
| | | { |
| | | while (!m_stoped) |
| | | do_once(nullptr); |
| | | } |
| | | |
| | | void run_for(long seconds) |
| | | { |
| | | time_t expired, now; |
| | | time(&now); |
| | | expired = now + seconds; |
| | | timeval tv = { seconds }; |
| | | do |
| | | { |
| | | do_once(&tv); |
| | | time(&now); |
| | | tv.tv_sec = expired - now; |
| | | tv.tv_usec = 0; |
| | | } while (!m_stoped && now < expired); |
| | | } |
| | | |
| | | void stop() |
| | | { |
| | | m_stoped = true; |
| | | } |
| | | |
| | | private: |
| | | class event_item : public qtl::event |
| | | { |
| | | public: |
| | | event_item(simple_event_loop* loop, qtl::socket_type fd) |
| | | : m_loop(loop), m_fd(fd), m_expired(LONG_MAX) |
| | | { |
| | | } |
| | | |
| | | virtual void set_io_handler(int flags, long timeout, std::function<void(int)>&& handler) NOEXCEPT override |
| | | { |
| | | if (timeout > 0) |
| | | { |
| | | time_t now; |
| | | time(&now); |
| | | if (m_expired > now + timeout) |
| | | m_expired = now + timeout; |
| | | m_loop->set(this, flags, m_expired); |
| | | } |
| | | else |
| | | { |
| | | m_expired = LONG_MAX; |
| | | m_loop->set(this, flags, 0); |
| | | } |
| | | m_io_handler = std::forward<std::function<void(int)>>(handler); |
| | | } |
| | | virtual void remove() override |
| | | { |
| | | m_loop->remove(this); |
| | | } |
| | | virtual bool is_busying() override |
| | | { |
| | | return m_io_handler!=nullptr; |
| | | } |
| | | |
| | | simple_event_loop* m_loop; |
| | | qtl::socket_type m_fd; |
| | | time_t m_expired; |
| | | std::function<void(int)> m_io_handler; |
| | | }; |
| | | std::vector<std::unique_ptr<event_item>> m_events; |
| | | |
| | | //implement for QTL |
| | | public: |
| | | template<typename Connection> |
| | | event_item* add(Connection* connection) |
| | | { |
| | | qtl::socket_type fd = connection->socket(); |
| | | event_item* result = new event_item(this, fd); |
| | | std::unique_ptr<event_item> item(result); |
| | | m_events.emplace_back(std::move(item)); |
| | | return result; |
| | | } |
| | | |
| | | template<typename Handler> |
| | | event_item* set_timeout(const timeval& timeout, Handler&& handler) |
| | | { |
| | | event_item* result = new event_item(this, 0); |
| | | std::unique_ptr<event_item> item(result); |
| | | ::time(&result->m_expired); |
| | | result->m_expired+=timeout.tv_sec; |
| | | if(m_expired>result->m_expired) |
| | | m_expired=result->m_expired; |
| | | m_events.emplace_back(std::move(item)); |
| | | return result; |
| | | } |
| | | |
| | | public: |
| | | void set(event_item* item, int flags, time_t expired) |
| | | { |
| | | if (item->m_fd + 1 > m_maxfd) |
| | | m_maxfd = item->m_fd + 1; |
| | | if (flags&qtl::event::ef_read) |
| | | FD_SET(item->m_fd, &m_readset); |
| | | if (flags&qtl::event::ef_write) |
| | | FD_SET(item->m_fd, &m_writeset); |
| | | if (flags&qtl::event::ef_exception) |
| | | FD_SET(item->m_fd, &m_exceptset); |
| | | if (expired > 0 && m_expired > expired) |
| | | m_expired = expired; |
| | | } |
| | | |
| | | void remove(event_item* item) |
| | | { |
| | | auto it = m_events.begin(); |
| | | while (it != m_events.end()) |
| | | { |
| | | if (it->get() == item) |
| | | { |
| | | m_events.erase(it); |
| | | return; |
| | | } |
| | | ++it; |
| | | } |
| | | } |
| | | |
| | | private: |
| | | fd_set m_readset, m_writeset, m_exceptset; |
| | | qtl::socket_type m_maxfd; |
| | | int do_once(timeval* timeout) |
| | | { |
| | | fd_set rs = m_readset, ws = m_writeset, es = m_exceptset; |
| | | timeval tv = { INT_MAX, 0 }; |
| | | time_t now; |
| | | time(&now); |
| | | if (timeout) |
| | | { |
| | | tv = *timeout; |
| | | timeout = &tv; |
| | | } |
| | | |
| | | long d = m_expired - now; |
| | | if (d > 0 && tv.tv_sec > d) |
| | | { |
| | | tv.tv_sec = d; |
| | | timeout = &tv; |
| | | } |
| | | |
| | | qtl::socket_type maxfd = m_maxfd; |
| | | FD_ZERO(&m_readset); |
| | | FD_ZERO(&m_writeset); |
| | | FD_ZERO(&m_exceptset); |
| | | m_maxfd = 0; |
| | | |
| | | if (maxfd == 0) |
| | | { |
| | | if (timeout) |
| | | { |
| | | std::this_thread::sleep_for(std::chrono::microseconds(timeout->tv_sec*std::micro::den + timeout->tv_usec)); |
| | | check_timeout(); |
| | | } |
| | | else |
| | | { |
| | | std::this_thread::sleep_for(std::chrono::seconds(1)); |
| | | } |
| | | return 0; |
| | | } |
| | | else |
| | | { |
| | | int ret = select(maxfd, &rs, &ws, &es, timeout); |
| | | if (ret > 0) |
| | | { |
| | | for (auto& item : m_events) |
| | | { |
| | | int flags = 0; |
| | | if (FD_ISSET(item->m_fd, &rs)) |
| | | flags |= qtl::event::ef_read; |
| | | if (FD_ISSET(item->m_fd, &ws)) |
| | | flags |= qtl::event::ef_write; |
| | | if (FD_ISSET(item->m_fd, &es)) |
| | | flags |= qtl::event::ef_exception; |
| | | if (flags && item->m_io_handler) |
| | | { |
| | | auto handler = std::move(item->m_io_handler); |
| | | handler(flags); |
| | | } |
| | | } |
| | | } |
| | | else if (ret == 0) |
| | | { |
| | | time(&now); |
| | | for (auto& item : m_events) |
| | | { |
| | | if (item->m_expired > 0 && item->m_io_handler && item->m_expired < now) |
| | | { |
| | | item->m_io_handler(qtl::event::ef_timeout); |
| | | item->m_expired = 0; |
| | | item->m_io_handler = nullptr; |
| | | } |
| | | } |
| | | } |
| | | else if (ret < 0) |
| | | { |
| | | int errc; |
| | | #ifdef _WIN32 |
| | | errc = WSAGetLastError(); |
| | | #else |
| | | errc = errno; |
| | | #endif |
| | | throw std::system_error(errc, std::system_category()); |
| | | } |
| | | return ret; |
| | | } |
| | | } |
| | | |
| | | void check_timeout() |
| | | { |
| | | time_t now; |
| | | time(&now); |
| | | for (auto& item : m_events) |
| | | { |
| | | if (item->m_expired > 0 && item->m_io_handler && item->m_expired < now) |
| | | { |
| | | item->m_io_handler(qtl::event::ef_timeout); |
| | | item->m_expired = 0; |
| | | item->m_io_handler = nullptr; |
| | | } |
| | | } |
| | | } |
| | | |
| | | time_t m_expired; |
| | | bool m_stoped; |
| | | }; |
| | | |
| | | simple_event_loop ev; |
| | | |
| | | using namespace qtl::mysql; |
| | | |
| | |
| | | |
| | | const char mysql_server[]="localhost"; |
| | | const char mysql_user[]="root"; |
| | | const char mysql_password[]=""; |
| | | const char mysql_password[]="123456"; |
| | | const char mysql_database[]="test"; |
| | | |
| | | void SimpleTest() |
| | | class MariaDBTest |
| | | { |
| | | async_connection connection; |
| | | ev.reset(); |
| | | connection.open(ev, [&connection](const error& e) { |
| | | if (e) |
| | | { |
| | | LogError(e); |
| | | ev.stop(); |
| | | } |
| | | else |
| | | { |
| | | printf("Connect to mysql ok.\n"); |
| | | connection.simple_query("select * from test", 0, [](MYSQL_ROW row, int field_count) { |
| | | for (int i = 0; i != field_count; i++) |
| | | printf("%s\t", row[i]); |
| | | printf("\n"); |
| | | return true; |
| | | }, [&connection](const error& e, size_t row_count) { |
| | | if (e) |
| | | LogError(e); |
| | | else |
| | | printf("Total %lu rows.\n", row_count); |
| | | public: |
| | | MariaDBTest() |
| | | { |
| | | Open(); |
| | | _service.run(); |
| | | } |
| | | |
| | | connection.close([]() { |
| | | printf("Close connection ok.\n"); |
| | | ev.stop(); |
| | | }); |
| | | }); |
| | | } |
| | | }, mysql_server, mysql_user, mysql_password, mysql_database); |
| | | private: |
| | | void Open(); |
| | | void Close(); |
| | | void SimpleQuery(); |
| | | void Execute(); |
| | | void Query(); |
| | | void MultiQuery(); |
| | | |
| | | ev.run(); |
| | | } |
| | | private: |
| | | async_connection _connection; |
| | | qtl::asio::service _service; |
| | | |
| | | void ExecuteTest() |
| | | { |
| | | async_connection connection; |
| | | ev.reset(); |
| | | connection.open(ev, [&connection](const error& e) { |
| | | if (e) |
| | | { |
| | | LogError(e); |
| | | ev.stop(); |
| | | } |
| | | else |
| | | { |
| | | printf("Connect to mysql ok.\n"); |
| | | connection.execute([&connection](const error& e, uint64_t affected) mutable { |
| | | if (e) |
| | | LogError(e); |
| | | else |
| | | printf("Insert %llu records ok.\n", affected); |
| | | connection.close([]() { |
| | | printf("Close connection ok.\n"); |
| | | ev.stop(); |
| | | }); |
| | | }, "insert into test(name, createtime, company) values(?, now(), ?)", 0, std::make_tuple("test name", "test company")); |
| | | } |
| | | }, mysql_server, mysql_user, mysql_password, mysql_database); |
| | | |
| | | ev.run(); |
| | | }; |
| | | |
| | | void QueryTest() |
| | | void MariaDBTest::Open() |
| | | { |
| | | async_connection connection; |
| | | ev.reset(); |
| | | connection.open(ev, [&connection](const error& e) { |
| | | _connection.open(_service, [this](const error& e) { |
| | | if (e) |
| | | { |
| | | LogError(e); |
| | | ev.stop(); |
| | | _service.stop(); |
| | | } |
| | | else |
| | | { |
| | | printf("Connect to mysql ok.\n"); |
| | | connection.query("select id, name, CreateTime, Company from test", 0, |
| | | [](int64_t id, const std::string& name, const qtl::mysql::time& create_time, const std::string& company) { |
| | | char szTime[128] = { 0 }; |
| | | if (create_time.year != 0) |
| | | { |
| | | struct tm tm; |
| | | create_time.as_tm(tm); |
| | | strftime(szTime, 128, "%c", &tm); |
| | | } |
| | | printf("%lld\t%s\t%s\t%s\n", id, name.data(), szTime, company.data()); |
| | | }, [&connection](const error& e) { |
| | | printf("query has completed.\n"); |
| | | if (e) |
| | | LogError(e); |
| | | |
| | | connection.close([]() { |
| | | printf("Close connection ok.\n"); |
| | | ev.stop(); |
| | | }); |
| | | }); |
| | | SimpleQuery(); |
| | | } |
| | | }, mysql_server, mysql_user, mysql_password, mysql_database); |
| | | |
| | | ev.run(); |
| | | } |
| | | |
| | | void MultiQueryTest() |
| | | void MariaDBTest::Close() |
| | | { |
| | | async_connection connection; |
| | | ev.reset(); |
| | | connection.open(ev, [&connection](const error& e) { |
| | | _connection.close([this]() { |
| | | printf("Connection is closed.\n"); |
| | | _service.stop(); |
| | | }); |
| | | } |
| | | |
| | | void MariaDBTest::SimpleQuery() |
| | | { |
| | | _connection.simple_query("select * from test", 0, [](MYSQL_ROW row, int field_count) { |
| | | for (int i = 0; i != field_count; i++) |
| | | printf("%s\t", row[i]); |
| | | printf("\n"); |
| | | return true; |
| | | }, [this](const error& e, size_t row_count) { |
| | | if (e) |
| | | { |
| | | LogError(e); |
| | | ev.stop(); |
| | | } |
| | | else |
| | | { |
| | | printf("Connect to mysql ok.\n"); |
| | | connection.query_multi("call test_proc", |
| | | [&connection](const error& e) { |
| | | if (e) |
| | | LogError(e); |
| | | |
| | | connection.close([]() { |
| | | printf("Close connection ok.\n"); |
| | | ev.stop(); |
| | | }); |
| | | }, [](uint32_t i, const std::string& str) { |
| | | printf("0=\"%d\", 'hello world'=\"%s\"\n", i, str.data()); |
| | | }, [](const qtl::mysql::time& time) { |
| | | struct tm tm; |
| | | time.as_tm(tm); |
| | | printf("current time is: %s\n", asctime(&tm)); |
| | | }); |
| | | printf("Total %lu rows.\n", row_count); |
| | | Execute(); |
| | | } |
| | | }, mysql_server, mysql_user, mysql_password, mysql_database); |
| | | }); |
| | | } |
| | | |
| | | ev.run(); |
| | | void MariaDBTest::Execute() |
| | | { |
| | | _connection.simple_query("select * from test", 0, [](MYSQL_ROW row, int field_count) { |
| | | for (int i = 0; i != field_count; i++) |
| | | printf("%s\t", row[i]); |
| | | printf("\n"); |
| | | return true; |
| | | }, [this](const error& e, size_t row_count) { |
| | | if (e) |
| | | LogError(e); |
| | | else |
| | | { |
| | | printf("Total %lu rows.\n", row_count); |
| | | Query(); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | void MariaDBTest::Query() |
| | | { |
| | | _connection.query("select id, name, CreateTime, Company from test", 0, |
| | | [](int64_t id, const std::string& name, const qtl::mysql::time& create_time, const std::string& company) { |
| | | char szTime[128] = { 0 }; |
| | | if (create_time.year != 0) |
| | | { |
| | | struct tm tm; |
| | | create_time.as_tm(tm); |
| | | strftime(szTime, 128, "%c", &tm); |
| | | } |
| | | printf("%lld\t%s\t%s\t%s\n", id, name.data(), szTime, company.data()); |
| | | }, [this](const error& e) { |
| | | printf("query has completed.\n"); |
| | | if (e) |
| | | LogError(e); |
| | | else |
| | | MultiQuery(); |
| | | }); |
| | | } |
| | | |
| | | void MariaDBTest::MultiQuery() |
| | | { |
| | | _connection.query_multi("call test_proc", |
| | | [this](const error& e) { |
| | | if (e) |
| | | LogError(e); |
| | | else |
| | | Close(); |
| | | |
| | | }, [](uint32_t i, const std::string& str) { |
| | | printf("0=\"%d\", 'hello world'=\"%s\"\n", i, str.data()); |
| | | }, [](const qtl::mysql::time& time) { |
| | | struct tm tm; |
| | | time.as_tm(tm); |
| | | printf("current time is: %s\n", asctime(&tm)); |
| | | }); |
| | | } |
| | | |
| | | int main(int argc, char* argv[]) |
| | | { |
| | | ExecuteTest(); |
| | | SimpleTest(); |
| | | QueryTest(); |
| | | MultiQueryTest(); |
| | | MariaDBTest test; |
| | | return 0; |
| | | } |
| | |
| | | PCH_HEADER=stdafx.h |
| | | PCH=stdafx.h.gch |
| | | OBJ=TestMariaDB.o |
| | | CFLAGS=-g -D_DEBUG -O2 -I/usr/include/mariadb -I/usr/local/include |
| | | CFLAGS=-g -D_DEBUG -O2 -I/usr/include -I/usr/include/mariadb -I/usr/local/include -I/usr/local/include/mariadb |
| | | CXXFLAGS=-I../include -std=c++11 |
| | | LDFLAGS= -L/usr/local/lib -L/usr/local/mariadb/lib -lmariadb |
| | | |