Delphi中如何多线程 *** 作数据库中的数据表

Delphi中如何多线程 *** 作数据库中的数据表,第1张

1。通过线程的互斥来同步 *** 作数据 2。数据库采用事务处理表中的数据 3。采用共享方式打开数据库,不是以独占方式打开数据库 建立一个mysql连接表加上一个临界区,表结点是这样的(mysqlcon,bool),根据实际情况定大校我用的是10个连接。

以mysql来说,可能出现脏读、不可重复读以及幻读,mysql默认设置是可重复读,即一次事务中不会读取到不同的数据。

可以做如下 *** 作:

1)打开两个客户端,均设置为RR;

2)在一个事务中,查询某个 *** 作查到某份数据;比如是某个字段version=1存在数据;

3)在另一个事务中,删除这份version=1的数据;删除后,在2所属的事务中查询数据是没有变化的,还是存在version=1的数据;

4)当我们在2所属的事务中继续更新数据,那么会发现更新不了,明明我们就看到了这份version=1的数据;

缓存一致性:

缓存一致,与什么一致?是与数据库一致,对外查询每个时刻一致;所以在针对于缓存与数据库之间该先更新哪一个呢?可能有人觉得我先更新数据库,再更新缓存不就行了吗?但是有想过个问题吗?

当用户已经支付成功了,更新到数据库,但是呢?你还在缓存中显示未支付,在用户点击频率很高并且数据库压力过大,来不及同步到缓存时,那你是不是很尴尬,这就是典型的不一致了。此时用户再支付,那你又告诉他已经支付了,那他会把你骂死的

那该怎么来做呢?我们可以这样,先更新缓存再更新数据库,那么存在什么问题呢?

1)缓存更新成功,但是数据库更新失败,而被其它的并发线程访问到

2)缓存淘汰成功,但是数据库更新失败,这也会引发后期数据不一致

你的提问就有问题

当你的程序不管是不是多线程的

获得到一个数据库连接是 数据库会把这个连接标记为繁忙 当其他程序访问时它会返回另外空闲的连接

连接个数是有限的 如果一直不释放连接 数据库就会告诉你连接已经使用完了

这里和线程安全有何关系呢? 线程安全和数据库 *** 作没有直接关系

1共用一个连接就可以 2其实一样可以用lock实现,把数据库 *** 作写成一个函数,函数内加lock。c#会安排他们排队 比如 private static object privateObjectLock = new object(); public static xxoo() { lock(privateObjectLock) { //数据 *** 作语句 } } } 你在一个函数里实现数据库 *** 作。然后线程 *** 作数据库都调用他

以mysql为数据库写的一个粗陋的demo,你参考一下,希望不会因为代码过多被百度吞了——

import javasqlConnection;

import javasqlDriverManager;

import javasqlPreparedStatement;

import javasqlResultSet;

import javasqlSQLException;

import javautilArrayList;

import javautilList;

public class Test {

       

    public static void main(String[] args) {

        allotThread();

    }

       

    /

      将100条数据分成10份并启动10个线程分别 *** 作

     /

    public static void allotThread() {

        List<String[]> datas = buildDatas();

        for (int i=0; i<100; i+=10) {

            List<String[]> tenDatas = datassubList(i, i + 10);

            insertData(tenDatas);

        }

    }

       

    /

      创建100条模拟数据

      @return

     /

    public static List<String[]> buildDatas() {

        List<String[]> datas = new ArrayList<String[]>();

        for (int i=0; i<100; i++) {

            String[] data = {"id " + i, "name " + i};

            datasadd(data);

        }

        return datas;

    }

       

    /

      启动线程进行数据插入 *** 作

      @param tenDatas

     /

    public static void insertData(final List<String[]> tenDatas) {

        new Thread(new Runnable() {

            public void run() {

                String sql = "insert into testtable (id, name) values (, )";

                Connection conn = null;

                PreparedStatement pstmt = null;

                try {

                    conn = getConnection();

                    connsetAutoCommit(false);

                    pstmt = getPstmt(conn, sql);

                    for (String[] data : tenDatas) {

                        pstmtsetString(1, data[0]);

                        pstmtsetString(2, data[1]);

                        pstmtaddBatch();

                    }

                    pstmtexecuteBatch();

                    conncommit();

                    connsetAutoCommit(true);

                } catch (SQLException e) {

                    eprintStackTrace();

                    rollback(conn);

                } catch (ClassNotFoundException e) {

                    eprintStackTrace();

                } finally {

                    close(pstmt);

                    close(conn);

                }

            }

        })start();

    }

       

    public static Connection getConnection() throws SQLException, ClassNotFoundException {

        ClassforName("commysqljdbcDriver");

        String dbUrl = "jdbc:mysql://localhost/testuseUnicode=true&characterEncoding=UTF-8";

        Connection conn = DriverManagergetConnection(dbUrl, "root", "tooeasy");

        return conn;

    }

       

    public static PreparedStatement getPstmt(Connection conn, String sql) throws SQLException, ClassNotFoundException {

        PreparedStatement pstmt = connprepareStatement(sql);

        return pstmt;

    }

       

    public static void rollback(Connection conn) {

        try {

            if (null != conn) {

                connrollback();

            }

        } catch (SQLException e) {

            eprintStackTrace();

        }

    }

       

    public static void close(Connection conn) {

        try {

            if (null != conn) {

                connclose();

            }

        } catch (SQLException e) {

            eprintStackTrace();

        }

    }

       

    public static void close(PreparedStatement pstmt) {

        try {

            if (null != pstmt) {

                pstmtclose();

            }

        } catch (SQLException e) {

            eprintStackTrace();

        }

    }

       

    public static void close(ResultSet rs) {

        try {

            if (null != rs) {

                rsclose();

            }

        } catch (SQLException e) {

            eprintStackTrace();

        }

    }

}

首先对数据库(尤其是Access)使用多线程大多不会提高效率(除非SQL中有耗时但不好资源的 *** 作,如T-SQL中休眠之类的语句)。

建议楼主:使用队列,将要执行的SQL语句放入队列中(如:SystemCollectionQueue或ArrayList),然后用一根线程一条一条执行,另外Access不支持事物回滚只有自己想办法实现了。滥用多线程会加大程序开发的难度,以及包括程序的不稳定。

另外:cbyvft的答案“……所有的线程使用同一个连接”

,是严重错误的!!连接对象Connection不能迸发,也就是不能多根线程共享一个连接对象,否则很容易引发异常(报错为:基础对象与RAW分离之类的信息)。

若非要用多线程来做,我可以给你一段代码(我以前开发的项目中一部分),请加我的“百度Hi”并发消息给我,我传给你。

我不在这里帖代码了,因为实现的代码较多,而且比较复杂(使用多线程要考虑很多问题,代码要硕壮通用,所以代码量较大)。

以上就是关于Delphi中如何多线程 *** 作数据库中的数据表全部的内容,包括:Delphi中如何多线程 *** 作数据库中的数据表、如何保证多线程从mysql数据库查询的数据不重复、请教多线程数据库程序如何保证线程安全等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/sjk/9494694.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-28
下一篇2023-04-28

发表评论

登录后才能评论

评论列表(0条)

    保存