前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >PostgreSQL的PDF.NET驱动程序构建过程

PostgreSQL的PDF.NET驱动程序构建过程

作者头像
用户1177503
发布于 2018-02-26 10:24:53
发布于 2018-02-26 10:24:53
1.4K00
代码可运行
举报
文章被收录于专栏:程序员的SOD蜜程序员的SOD蜜
运行总次数:0
代码可运行

目前有两种主要的PostgreSQL的.NET驱动程序,分别是Npgsql和dotConnector for PostgreSQL(以下简称dotConnector),这两者都是第三方的.NET Provider,本文将大致讲解一下这两个驱动程序的安装方式,并讲解如何利用它们构建PDF.NET的驱动程序,使得PDF.NET数据开发框架可以支持访问PostgreSQL数据库

一、安装PostgreSQL的.NET驱动程序

1,Npgsql的安装:

PostgreSQL数据库程序可以去官网 http://www.postgresql.org/ 下载,在写本篇文章的时候,最新版本已经是9.1了,我下载使用的是9.0.4. 下载安装以后,打开程序 Application Stack Builder,选择已经安装好的数据库以后,单击下一步进入到如下界面 

在Datase Drivers选项中,这里选择Npgsql v2.0.11-1,其它驱动程序根据需要安装。选择好以后,按照提示一步步即可完整安装好.NET的数据驱动程序。

2,dotConnect For PostgreSQL 安装

在网上搜索一下这个驱动程序,我是从下面的地址安装的:

http://wzmcc.newhua.com/soft/92182.htm

安装文件名是 dcpostgresqlfree.exe,版本是 5.30.160,安装的时候会选择是否将程序集编译到GAC中。安装完成以后在安装目录会有几个简单的示例程序解决方案:

大家可以打开示例程序解决方案看看,都很简单,具体如何使用可以看本篇文章的下面部分。

二、构建PDF.NET For PostgreSQL驱动程序

根据上面的步骤,安装了.NET的PostgreSQL驱动程序以后,就可以直接按照示例来访问PostgreSQL数据库了,但这两种不同的驱动程序让我们难以选择使用哪一种,而且它们直接提供的ADO.NET实现用起来也不是十分方便,我们有必要将它们包装一下,简化使用方式。PDF.NET数据开发框架内置了MS DAAB类似的AdoHelper数据访问抽象类,所以只要继承该类就可以拥有PDF.NET强大的数据访问能力。

1,包装Ngpsql驱动程序

下面以Npgsql为例,看看如何让PDF.NET支持PostgreSQL。下面是贴出全部代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
using System;
using System.Collections.Generic;
//using System.Linq;
using System.Text;
using System.Data;
using Npgsql ;
namespace PWMIS.DataProvider.Data
{
    /// <summary>
    /// PostgreSQL数据访问类
    /// </summary>
    public class PostgreSQL : AdoHelper
    {
        /// <summary>
        /// 默认构造函数
        /// </summary>
        public PostgreSQL()
        {
            //
            // TODO: 在此处添加构造函数逻辑
            //
        }
        /// <summary>
        /// 获取当前数据库类型的枚举
        /// </summary>
        public override PWMIS.Common.DBMSType CurrentDBMSType
        {
            get { return PWMIS.Common.DBMSType.PostgreSQL ; } 
        }
        /// <summary>
        /// 创建并且打开数据库连接
        /// </summary>
        /// <returns>数据库连接</returns>
        protected override IDbConnection GetConnection()
        {
            IDbConnection conn = base.GetConnection();
            if (conn == null)
            {
                conn = new NpgsqlConnection (base.ConnectionString);
                //conn.Open ();
            }
            return conn;
        }
        /// <summary>
        /// 获取数据适配器实例
        /// </summary>
        /// <returns>数据适配器</returns>
        protected override IDbDataAdapter GetDataAdapter(IDbCommand command)
        {
            IDbDataAdapter ada = new NpgsqlDataAdapter((NpgsqlCommand)command);
            return ada;
        }
        /// <summary>
        /// 获取一个新参数对象
        /// </summary>
        /// <returns>特定于数据源的参数对象</returns>
        public override IDataParameter GetParameter()
        {
            return new NpgsqlParameter();
        }
        /// <summary>
        ///  获取一个新参数对象
        /// </summary>
        /// <param name="paraName">参数名</param>
        /// <param name="dbType">参数数据类型</param>
        /// <param name="size">参数大小</param>
        /// <returns>特定于数据源的参数对象</returns>
        public override IDataParameter GetParameter(string paraName, System.Data.DbType dbType, int size)
        {
            NpgsqlParameter para = new NpgsqlParameter();
            para.ParameterName = paraName;
            para.DbType = dbType;
            para.Size = size;
            return para;
        }
        /// <summary>
        /// 返回此 NpgsqlConnection 的数据源的架构信息。
        /// </summary>
        /// <param name="collectionName">集合名称</param>
        /// <param name="restrictionValues">请求的架构的一组限制值</param>
        /// <returns>数据库架构信息表</returns>
        public override DataTable GetSchema(string collectionName, string[] restrictionValues)
        {
            using (NpgsqlConnection conn = (NpgsqlConnection)this.GetConnection())
            {
                conn.Open();
                if (restrictionValues == null && string.IsNullOrEmpty(collectionName))
                    return conn.GetSchema();
                else if (restrictionValues == null && !string.IsNullOrEmpty(collectionName))
                {
                    if (collectionName == "Procedures")
                        return this.getProcedures();
                    else
                        return conn.GetSchema(collectionName); //Procedures
                }
                else
                { 
                    if (collectionName == "ProcedureParameters")
                        return getFunctionArgsInfo(restrictionValues[2]);
                    else
                        return conn.GetSchema(collectionName, restrictionValues);
                }
            }
        }
        /// <summary>
        /// 预处理SQL语句,语句中不能包含"`"(反引号,tab键上面的那个符号)号,如果需要,请使用参数化查询。
        /// </summary>
        /// <param name="SQL"></param>
        /// <returns></returns>
        protected override string PrepareSQL(ref string SQL)
        {
            return SQL.Replace("[", "\"").Replace("]", "\"");
        }
        /// <summary>
        /// 获取或者设置自增列对应的序列名称
        /// </summary>
        public override string InsertKey
        {
            get
            {
                return string.Format("select currval('\"{0}\"')",base.InsertKey );
            }
            set
            {
                base.InsertKey = value;
            }
        }
        /// <summary>
        /// 定义获取PostgreSQL的函数参数的函数
        /// <seealso cref="http://www.alberton.info/postgresql_meta_info.html"/>
        /// </summary>
        private void createFunctionArgsInfo()
        {
            //由于函数定义语句较长,放到了资源文件中
            string sql = PWMIS.PostgreSQLClient.Properties.Resources.sql_function_args;
            this.SqlServerCompatible = false;
            this.ExecuteNonQuery(sql);
        }
        /// <summary>
        /// 获取函数的参数信息
        /// </summary>
        /// <param name="functionName">函数名</param>
        /// <returns></returns>
        private DataTable  getFunctionArgsInfo(string functionName)
        {
            string sql = string.Format("select * from function_args('{0}','public');", functionName);
            DataSet ds = null;
            try
            {
                ds= this.ExecuteDataSet(sql);
            }
            catch
            {
                createFunctionArgsInfo();
                ds = this.ExecuteDataSet(sql);
            }
           
            DataTable dt = ds.Tables[0];
            dt.Columns["pos"].ColumnName = "ordinal_position";
            dt.Columns["argname"].ColumnName = "PARAMETER_NAME";
            dt.Columns["datatype"].ColumnName = "DATA_TYPE";
            dt.Columns["direction"].ColumnName = "PARAMETER_MODE";
            dt.Columns.Add("IS_RESULT", typeof(string));
            dt.Columns.Add("CHARACTER_MAXIMUM_LENGTH", typeof(int));
            foreach (DataRow row in dt.Rows)
            {
                if(row["PARAMETER_NAME"] == DBNull.Value)  row["PARAMETER_NAME"] =  ""; 
                row["IS_RESULT"] = row["PARAMETER_NAME"].ToString() == "RETURN VALUE" ? "YES" : "NO";
                row["PARAMETER_MODE"] = row["PARAMETER_MODE"].ToString() == "o" ? "OUT" : row["PARAMETER_MODE"].ToString() == "i" ? "IN" : row["PARAMETER_MODE"];
            }
            return dt;
        }
        private DataTable getProcedures()
        {
            string sql = @"SELECT routine_name
  FROM information_schema.routines
 WHERE specific_schema NOT IN
       ('pg_catalog', 'information_schema')
   AND type_udt_name != 'trigger';";
            return this.ExecuteDataSet(sql).Tables[0];
        }
    }
}

 注意上面程序中的 PrepareSQL 方法,它将SQLSERVER格式的SQL语句转换成PostgreSQL支持的格式,SQLSERVER使用成对的中括号来限定对象名,而PostgreSQL使用双引号,尤其在对象名称使用了大小写混合的情况。另外程序为了支持获取数据库的架构信息,重写了AdoHelper的抽象方法GetSchema,有关PostgreSQL具体获取表架构信息的内容,请参看 http://www.alberton.info/postgresql_meta_info.html

2,包装dotConnect驱动程序

程序代码与使用Npgsql类似,区别主要是将上面代码中的Npgsql字样替换成PgSql即可,引用Devart.Data.dll,Devart.Data.PostgreSql.dll,使用下面的名称空间:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
using Devart.Data.PostgreSql;

由于dotConnect的驱动程序采用Oracle驱动程序的风格,要求SQL语句的参数使用“:”作为参数名称,而不是SqlServer样式的“@”,所以下面的方法需要重写:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/// <summary>
        /// 预处理SQL语句,语句中不能包含中括号,如果需要,请使用参数化查询。
        /// </summary>
        /// <param name="SQL"></param>
        /// <returns></returns>
        protected override string PrepareSQL(ref string SQL)
        {
            return SQL.Replace("[", "\"").Replace("]", "\"").Replace("@",":");
        }
        public override string GetParameterChar
        {
            get
            {
                return ":";
            }
        }

到此为止,使用dotConnect做PDF.NET的PostgreSQL驱动程序也做好了。

三、使用PDF.NET For PostgreSQL驱动程序

1,使用配置

假定上面使用Npgsql和dotConnect驱动的程序分别是 PWMIS.PostgreSQLClient 程序集中的程序,名称分别是

PWMIS.DataProvider.Data.PostgreSQL

PWMIS.DataProvider.Data.dotConnectPostgreSQL

那么我们在应用程序配置文件里面如下使用即可:

使用Npgsql访问:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<add name="ConnectionSetting" connectionString="server=192.168.XX.XX;User Id=postgres;password=XXXX;DataBase=XXDB" providerName="PWMIS.DataProvider.Data.PostgreSQL,PWMIS.PostgreSQLClient"/>

使用dotConnect访问:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<add name="ConnectionSetting" connectionString="server=192.168.XX.XX;User Id=postgres;password=XXXX;DataBase=XXDB" providerName="PWMIS.DataProvider.Data.dotConnectPostgreSQL,PWMIS.PostgreSQLClient"/>

2,执行效率区别

使用这两个不同的提供程序数据访问效率有什么区别呢?经过测试,它们之间仅有细微的差别,Npgsql略微胜出,下面是测试程序建立过程:

首先在SqlMap.config文件中建立一个PostgreSQL的数据访问脚本:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<Select CommandName="GetFundFeat" Method="" CommandType="Text" Description="获取业绩" ResultClass="DataSet">
<![CDATA[SELECT * FROM GetFundTrend_FundAnalysis_FundFeat (#currentJJDM:String#,#OtherJJDM:String#)]]>
</Select>

然后使用集成开发工具的代码生成器生成一个类中下面的方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public DataSet GetFundFeat(String currentJJDM  , String OtherJJDM   ) 
    { 
            //获取命令信息
            CommandInfo cmdInfo=Mapper.GetCommandInfo("GetFundFeat");
            //参数赋值,推荐使用该种方式;
            cmdInfo.DataParameters[0].Value = currentJJDM;
            cmdInfo.DataParameters[1].Value = OtherJJDM;
            //参数赋值,使用命名方式;
            //cmdInfo.SetParameterValue("@currentJJDM", currentJJDM);
            //cmdInfo.SetParameterValue("@OtherJJDM", OtherJJDM);
            //执行查询
            return CurrentDataBase.ExecuteDataSet(CurrentDataBase.ConnectionString, cmdInfo.CommandType, cmdInfo.CommandText , cmdInfo.DataParameters);
        //
    }//End Function

最后以不同的Pgsql驱动程序运行程序,查看执行的SQL日志

使用dotConnect访问:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//2011/5/30 16:52:44 @AdoHelper 执行命令:
SQL="SELECT * FROM GetFundTrend_FundAnalysis_FundFeat (:currentJJDM,:OtherJJDM)"
//命令类型:Text
//2个命令参数:
Parameter["currentJJDM"]    =    "KF0355"              //DbType=AnsiString
Parameter["OtherJJDM"]    =    "000001,399001,H11020,000300"              //DbType=AnsiString
//2011/5/30 16:52:44 @AdoHelper :Execueted Time(ms):448

使用Npgsql访问:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//2011/5/30 16:58:17 @AdoHelper 执行命令:
SQL="SELECT * FROM GetFundTrend_FundAnalysis_FundFeat (@currentJJDM,@OtherJJDM)"
//命令类型:Text
//2个命令参数:
Parameter["@currentJJDM"]    =    "KF0180"              //DbType=String
Parameter["@OtherJJDM"]    =    "000001,399001,H11020,000300"              //DbType=String
//2011/5/30 16:58:17 @AdoHelper :Execueted Time(ms):405

有关PDF.NET数据开发框架的详细信息,请看官网说明:http://www.pwmis.com/sqlmap

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
quarkus依赖注入之五:拦截器(Interceptor)
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本文是《quarkus依赖注入》系列的第五篇,经过前面的学习,咱们熟悉了依赖注入的基本特性,接下来进一步了解相关的高级特性,先从本篇的拦截器开始 如果您熟悉spring的话,对拦截器应该不会陌生,通过拦截器可以将各种附加功能与被拦截代码的主体解耦合,例如异常处理、日志、数据同步等多种场景 本篇会演示如何自定义拦截器,以及如何对bean的方法进行进行拦截
程序员欣宸
2022/04/13
1.4K1
quarkus依赖注入之五:拦截器(Interceptor)
quarkus依赖注入之六:发布和消费事件
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本文是《quarkus依赖注入》系列的第六篇,主要内容是学习事件的发布和接收 如果您用过Kafka、RabbitMQ等消息中间件,对消息的作用应该不会陌生,通过消息的订阅和发布可以降低系统之间的耦合性,这种方式也可以用在应用内部的多个模块之间,在quarkus框架下就是事件的发布和接收 本篇会演示quarkus应用中如何发布事件、如何接收事件,全文由以
程序员欣宸
2022/04/13
5830
quarkus依赖注入之六:发布和消费事件
quarkus依赖注入之一:创建bean
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 关于依赖注入 对一名java程序员来说,依赖注入应该是个熟悉的概念,简单的说就是:我要用XXX,但我不负责XXX的生产 以下代码来自spring官方,serve方法要使用MyComponent类的doWork方法,但是不负责MyComponent对象的实例化,只要用注解Autowired修饰成员变量myComponent,spring环境会负责为myCompon
程序员欣宸
2022/04/13
1.1K0
quarkus依赖注入之一:创建bean
C++读写锁介绍_数据库读写锁
先看看互斥锁,它只有两个状态,要么是加锁状态,要么是不加锁状态。假如现在一个线程a只是想读一个共享变量 i,因为不确定是否会有线程去写它,所以我们还是要对它进行加锁。但是这时又有一个线程b试图去读共享变量 i,发现被锁定了,那么b不得不等到a释放了锁后才能获得锁并读取 i 的值,但是两个读取操作即使是同时发生的,也并不会像写操作那样造成竞争,因为它们不修改变量的值。所以我们期望在多个线程试图读取共享变量的时候,它们可以立刻获取因为读而加的锁,而不是需要等待前一个线程释放。
全栈程序员站长
2022/09/22
8710
quarkus依赖注入之三:用注解选择注入bean
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本文是《quarkus依赖注入》系列的第三篇,前文咱们掌握了创建bean的几种方式,本篇趁热打铁,学习一个与创建bean有关的重要知识点:一个接口如果有多个实现类时,bean实例应该如何选择其中的一个呢?可以用注解来设定bean的选择逻辑 如果您熟悉spring,此刻应该会想到ConditionalXXX注解,下面的代码来自spring官方,注解Con
程序员欣宸
2022/04/13
7560
quarkus依赖注入之三:用注解选择注入bean
如何理解互斥锁、条件变量、读写锁以及自旋锁?
锁是一个常见的同步概念,我们都听说过加锁(lock)或者解锁(unlock),当然学术一点的说法是获取(acquire)和释放(release)。
果冻虾仁
2021/12/08
1.6K0
如何理解互斥锁、条件变量、读写锁以及自旋锁?
quarkus依赖注入之十二:禁用类级别拦截器
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本篇是《quarkus依赖注入》系列的第十二篇,继续学习拦截器的另一个高级特性:禁用类级别拦截器 本篇由以下内容构成 编码验证类拦截器和方法拦截器的叠加效果 用注解NoClassInterceptors使类拦截器失效 总的来说,本篇内容非常简单,就是说清楚NoClassInterceptors注解用在哪里,怎么用,可以轻松愉快的阅读 类拦截器和方法
程序员欣宸
2022/05/06
4180
quarkus依赖注入之十二:禁用类级别拦截器
quarkus依赖注入之十一:拦截器高级特性上篇(属性设置和重复使用)
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本篇是《quarkus依赖注入》系列的第十一篇,之前的[《拦截器》]学习了拦截器的基础知识,现在咱们要更加深入的了解拦截器,掌握两种高级用法:拦截器属性和重复使用拦截器 先来回顾拦截器的基本知识,定义一个拦截器并用来拦截bean中的方法,总共需要完成以下三步 业务需求设定 为了让本篇所学知识点显得有实用型,这里假定一个业务需求,然后咱们用拦
程序员欣宸
2022/05/06
6880
quarkus依赖注入之十一:拦截器高级特性上篇(属性设置和重复使用)
quarkus依赖注入之八:装饰器(Decorator)
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本篇是《quarkus依赖注入》系列的第八篇,目标是掌握quarkus实现的一个CDI特性:装饰器(Decorator) 提到装饰器,熟悉设计模式的读者应该会想到装饰器模式,个人觉得下面这幅图很好的解释了装饰器模式,左下角的红框是关键点:自己的send方法中,先调用父类的send(也就是被装饰类的send),然后才是自己的业务逻辑 quarku
程序员欣宸
2022/05/06
6270
quarkus依赖注入之八:装饰器(Decorator)
【Linux】多线程(自旋锁、读写锁)
自旋锁是一种多线程同步机制,用于保护共享资源免受并发访问的影响。在多个线程尝试获取锁时,它们会持续自旋(即在一个循环中不断检查锁是否可用)而不是立即进入休眠状态等待锁的释放。这种机制减少了线程切换的开销,适用于短时间内锁的竞争情况。但是不合理的使用,可能会造成 CPU 的浪费。
秦jh
2024/12/03
1480
【Linux】多线程(自旋锁、读写锁)
quarkus依赖注入之二:bean的作用域
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 关于bean的作用域(scope) 官方资料:https://lordofthejars.github.io/quarkus-cheat-sheet/#_injection 作为《quarkus依赖注入》系列的第二篇,继续学习一个重要的知识点:bean的作用域(scope),每个bean的作用域是唯一的,不同类型的作用域,决定了各个bean实例的生命周期,例
程序员欣宸
2022/04/13
5770
quarkus依赖注入之二:bean的作用域
详解Linux多线程中互斥锁、读写锁、自旋锁、条件变量、信号量
---- Hello、Hello大家好,我是木荣,今天我们继续来聊一聊Linux中多线程编程中的重要知识点,详细谈谈多线程中同步和互斥机制。 同步和互斥 互斥:多线程中互斥是指多个线程访问同一资源时同时只允许一个线程对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的; 同步:多线程同步是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源
Linux兵工厂
2023/02/28
3.7K0
详解Linux多线程中互斥锁、读写锁、自旋锁、条件变量、信号量
quarkus依赖注入之四:选择注入bean的高级手段
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本文是《quarkus依赖注入》系列的第四篇,在应用中,一个接口有多个实现是很常见的,那么依赖注入时,如果类型是接口,如何准确选择实现呢?前文介绍了五种注解,用于通过配置项、profile等手段选择注入接口的实现类,面对复杂多变的业务场景,有时候仅靠这两种手段是不够的,最好是有更自由灵活的方式来选择bean,这就是本篇的内容,通过注解、编码等更多方式选
程序员欣宸
2022/04/13
9020
quarkus依赖注入之四:选择注入bean的高级手段
面试系列之-读写锁(JAVA基础)
读写锁的内部包含两把锁:一把是读(操作)锁,是一种共享锁;另一把是写(操作)锁,是一种独占锁。在没有写锁的时候,读锁可以被多个线程同时持有。写锁是具有排他性的:如果写锁被一个线程持有,其他的线程不能再持有写锁,抢占写锁会阻塞;进一步来说,如果写锁被一个线程持有,其他的线程不能再持有读锁,抢占读锁也会阻塞。
用户4283147
2023/09/11
4550
面试系列之-读写锁(JAVA基础)
Java读写锁浅析
Java读写锁,也就是ReentrantReadWriteLock,其包含了读锁和写锁,其中读锁是可以多线程共享的,即共享锁,而写锁是排他锁,在更改时候不允许其他线程操作。读写锁底层是同一把锁(基于同一个AQS),所以会有同一时刻不允许读写锁共存的限制。
luoxn28
2021/05/13
3K0
ReadWriteLock 读写锁实现一个缓存
实际工作中我们会遇到一种并发场景:读多写少,这个时候为了优化性能,我们就会使用缓存。针对读多写少这种并发场景,Java SDK 并发包提供了读写锁——ReentrantReadWriteLock,非常容易使用,并且性能很好。通过本文学会如何写出一个缓存组件,以及锁降级是什么?
码哥字节
2020/03/24
1K0
腾讯面试:什么锁比读写锁性能更高?
在并发编程中,读写锁 ReentrantReadWriteLock 的性能已经算是比较高的了,因为它将悲观锁的粒度分的更细,在它里面有读锁和写锁,当所有操作为读操作时,并发线程是可以共享读锁同时运行的,这样就无需排队执行了,所以执行效率也就更高。
磊哥
2024/05/15
1150
互斥锁-读写锁-条件锁
不能拷贝互斥量变量,但可以拷贝指向互斥量的指针,这样就可以使多个函数或线程共享互斥量来实现同步。上面动态申请的互斥量需要动态的撤销。
CC老师
2023/03/23
8250
互斥锁-读写锁-条件锁
Java的乐观锁,悲观锁,读写锁,递归锁
我们都知道在 Java 中为了保证一些操作的安全性,就会涉及到使用锁,但是你对 Java 的锁了解的有多少呢?Java 都有哪些锁?以及他们是怎么实现的,今天了不起就来说说关于 Java 的锁。
Java极客技术
2024/01/31
2850
Java的乐观锁,悲观锁,读写锁,递归锁
【Linux】:多线程(读写锁 && 自旋锁)
🔥 读写锁(Read-Write Lock)是一种用于多线程环境下同步访问共享资源的锁。它与传统的互斥锁(Mutex)有所不同,提供了更细粒度的控制,以便提高并发性能。它允许多个线程同时 读取 数据,但在写入数据时,必须确保只有一个线程可以进行写操作,并且在写操作期间,所有的读操作都必须等待。
IsLand1314
2024/12/20
1960
【Linux】:多线程(读写锁 && 自旋锁)
推荐阅读
相关推荐
quarkus依赖注入之五:拦截器(Interceptor)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验