利用参数编辑器(Parameter Editor)来为参数赋值
具体方法是 选中TQuery部件 单击鼠标右键 然后从中选择Define Parameters 便可以打开参数编辑器
例如 在TQuery部件的SQL属性中我们设置如下的SQL语句
Setect From Customer Where CustNO=:Number;
TQuery的DatabaseName属性为DBDEMOS 其中Number为参数变量 我们便可以为参数Number赋值 在Datetype组合框中选择该参数的数据类型为整数Integer 在Value编辑框中可以为参数Number赋一个值 也可以单击Null Value检查框为参数Number赋一个空值Null 给参数赋值之后 单击OK按钮 这样TQuery部件中的SQL 查询便准备好了 而且参数值也被赋给了动态SQL语句中相应的参数 此时当把TQuery 部件的Active属性设置成True时 在与TQuery部件相连的数据浏览部件中会显示出查询结果 通过参数编辑器为参数赋值 这种方式缺乏应有的灵活性 在实际应用中用得较少 在实际应用中程序设计人员希望用更灵活方便的方式为参数赋值 那就是我们接下来要介绍的另一种途径
在运行过程中 通过程序为参数赋值
用这种方式为参数赋值有三种方法
①根据参数在SQL语句中出现的顺序 设置TQuery部件的Params属性值为参数赋值
②直接根据SQL语句中各参数的名字 调用ParamByName方法来为各参数赋值
③将TQuery部件的DataSource属性设置为另一个数据源 这样将另一个数据源中与当前TQuery部件的SQL语句中的参数名相匹配的字段值赋给其对应的参数
这三种方法我们将在下面的三小节中具体地介绍
使用Params属性为参数赋值
TQuery部件具有一个Params属性 它们在设计时不可用 在程序运行过程中可用 并且是动态建立的 当为TQuery部件编写动态SQL 语句时 Delphi 会自动地建立一个数组Params 数组Params是以 下标开始的 依次对应动态SQL 语句中的参数 也就是说动态SQL语句中第一个参数对应Params[ ] 第二个参数对应params[ ] 依此类推
例如 一个TQuery部件Query 我们为它编写的动态SQL语句是
Insert Into Customer(CustNo Name Country)
Values( CustNo :Name : Country)
对于上述这条动态SQL语句中的参数 我们可以利用TQuery部件的params 属性为参数赋值
Query params[ ] AsString := ;
Query params[ ] AsString := Lichtenstein ;
Query params[ ] AsString := USA ;
上述语句将把 赋给参数 Cuse_No Lichtenstein 赋给参数 Name USA 赋给参数 Country
使用ParamByName方法为参数赋值
ParamByName是一个函数 用动态SQL语句中的参数作为调用ParamByName函数的参数 这样便可以为它们赋值 使用这种赋值方法 必须要知道动态SQL语句参数的名字
例如在 节中的例子中 也可以用下述方法给参数赋值
Query ParamByName( CustNo ) AsString := ;
Query ParamByName( Name ) AsString := Lichtenstein ;
Query ParamByName( Country ) AsString := USA ;
使用这种方法同样可以为各参数赋值 而且更加直观一些
使用Datasource属性为参数赋值
上述两种方法的共同特点是 我们在为各参数赋值时 我们是知道各参数对应的具体参数值的 而在具体的应用程序中 有些参数值常常是无法确定的 例如参数值来自于另一个查询结果 对于这种情况 Delphi提供了使用Datasource属性为动态SQL 语句中尚存在没有赋值的参数时 Delphi 会自动检查 TQuery 部件的 Datasource 属性 如果为Datasource属性设置了属性值(该属性的值是另一个TDatasource部件的名字) Delphi 会把没有赋值的参数与TDatasource部件中的各字段比较 Delphi 会将相应的字段值赋给与其相匹配的参数 利用这种方法也能实现所谓的连接查询 我们在学习使用TTable部件时 便会创建主要 明细型数据库应用 用TQuery部件创建的连接查询与主要 明细型应用是相似的
例如 在如图 所示的应用中 设置了下列部件
● 一个TTable部件
名字为Cust 它的DatabaseName属性为DEMOS TableName属性为Customer
● 一个TDatasource部件
名字为Custsource 其Dataset属性被设置为Cust
● 一个TQuery部件
名字为ORDERS 其DatabaseName被设置为DEMOS SQL属性值为
Select Orders CustNo Orders OrderNo Orders SaleDate FROM Orders
WHERE Orders CustNo =: CustNo
ORDERS的DataSouce属性被设置为CustSource
● 一个TDatasource部件
名字为OrderSource 其DataSet属性被设置为Orders
● 两个TDBGrid部件
它们分别连接CustSource和OrderSource
TQuery部件Orders中的动态SQL语句中的参数 CustNo在程序设计过程中没有给它赋值 当该应用程序运行时Delphi会自动地到其Datasource属性中说明的数据源CustSource中查找与参数 CustNo匹配的字段 而CustSource中正好有一个名字为 CustNo 的字段与参数 CustNo匹配 这样Customer表中的CustNo字段值被赋给了参数 : CustNo 而当每移动Customer表中的记录指针 参数 CustNo的值会随之改变 而参数 CustNo的值发生改变时 Orders中的动态SQL语句会根据新的参数值重新查询 从数据库表中获取相应的订单数据 这样也变实现了类似于主要 明细型应用 即连接查询
Prepare方法的使用
在使用动态SQL语句编程时 常常用到一个很重要的方法prepare 调用prepare 方法之后 Delphi会将带参数的SQL语句传送给与其对应的数据库引擎 对动态SQL语句进行语法分析和优化 虽然在用动态SQL语句编程时 调用prepare方法并不是必须的 但是这里我们要极力推荐调用prepare方法 因为调用prepare方法后 会大大提高动态SQL 语句的执行性能 特别是当要反复多次执行同一条动态SQL语句时 其优越性会更加明显 如果在应用程序中执行一条SQL语句之前并没有显式地调用prepare方法 每次在执行SQL 语句时 Delphi会隐含地调用propare方法以准备这个查询
TQuery部件还有一个prepare属性 这是一个布尔型属性 当其属性值为True时 表明该查询已被准备好了( SQL 语句已被传送到数据库引擎中 ) 当我们使用参数编辑器Parameters Editor来为动态SQL语句中的参数赋值时 当设置完相应的参数值并退出参数编辑器时 Delphi会隐含地调用prepare方法以准备好查询
当SQL语句执行完之后 要想准备下一个查询 首先必须调用close方法 然后才能调用prepare方法准备下一个查询 一般来说 在一个应用程序中应该调用一次prepare方法 常常在窗体的OnCreate事件处理过程中调用prepare方法 然后用上述介绍的方法为参数赋值 最后调用Open方法或ExecSQL方法执行SQL语句 以完成查询
当然在调用prepare方法准备好一个查询时 会消耗一些数据库资源 因而每当一个查询执行完毕之后 要养成调用Unprepare方法以撤消查询的好习惯 在运行程序过程中 通过程序改变TQuery部件的SQL属性值时 Delphi会自动地调用Close方法和Unprepare 方法 以撤消查询
返回目录 DELPHI基础教程
编辑推荐
Java程序设计培训视频教程
J EE高级框架实战培训视频教程
Visual C++音频/视频技术开发与实战
Oracle索引技术
ORACLE G数据库开发优化指南
Java程序性能优化 让你的Java程序更快 更稳定
C嵌入式编程设计模式
Android游戏开发实践指南
lishixinzhi/Article/program/Delphi/201311/25147
CallableStatement 接口扩展 PreparedStatement,它提供了对输出和输入/输出参数的支持。CallableStatement 接口还具有对 PreparedStatement 接口提供的输入参数的支持。
CallableStatement 接口允许使用 SQL 语句来调用存储过程。存储过程是具有数据库接口的程序。这些程序拥有下列各项:
它们可以拥有输入和输出参数,或者既输入又输出的参数。
它们可以有返回值。
它们有能力返回多个 ResultSet。
在 JDBC 中,存储过程调用在概念上是对数据库的单一调用,但与存储过程相关联的程序可以拥有数以百计的数据库请求。存储过程程序还可以执行许多其它通常不是使用 SQL 语句执行的程序任务。
由于 CallableStatement 遵循将准备与处理阶段分开这种 PreparedStatement 模型,所以它们有可能进行最优重新使用(有关详细信息,参见 PreparedStatement)。由于存储过程的 SQL 语句绑定到程序中,所以可以将它们作为静态 SQL 处理,并且能够以该方式获得进一步的性能增益。一个以最优方式使用存储过程的示例是将许多数据库工作封装在单一可重新使用数据库调用中。只有这个调用将通过网络前往其它系统,但该请求可以在远程系统上完成许多工作。
创建 CallableStatement
使用 prepareCall 方法来创建新的 CallableStatement 对象。对于 prepareStatement 方法,必须在创建 CallableStatement 对象时提供 SQL 语句。在那个时候,对 SQL 语句进行预编译。例如,假定已存在名为 conn 的 Connection 对象,以下程序语句将创建 CallableStatement 对象并完成用于获取已可以在数据库中进行处理的 SQL 语句的准备阶段:
PreparedStatement ps = connprepareStatement(" = CALL ADDEMPLOYEE(, , ");
ADDEMPLOYEE 存储过程对新雇员姓名、他的社会保障号以及他的经理的用户标识接收输入参数。根据此信息,可使用关于雇员的信息(如他的开始日期、分公司以及部门,等等)来更新多个公司数据库表。此外,存储过程是一个可以生成该雇员的标准用户标识和电子邮件地址的程序。存储过程还可以将带有初始用户名和密码的电子邮件发送给雇用经理;然后,雇用经理可以将该信息提供给雇员。
ADDEMPLOYEE 存储过程设置为带有返回值。返回码可以是成功代码,也可以是在发生故障时可由调用程序使用的故障代码。还可以将返回值定义成新雇员的公司标识号。最后,存储过程程序可以以内部方式处理查询并保持来自那些查询的 ResultSet 处于打开状态且可供调用程序使用。通过所返回的 ResultSet 来查询有关新雇员的所有信息并使其可供调用者使用是合理的。
下列各节对如何完成每一种这些类型的任务作了阐述。
指定 ResultSet 特征和自动生成的键支持
对于 createStatement 和 prepareStatement,存在多个版本的 prepareCall,它们提供了对指定 ResultSet 特征的支持。与 prepareStatement 不同,prepareCall 方法未提供变体来使用来自 CallableStatement 的自动生成的键(JDBC 30 不支持此概念)。以下是一些有效 prepareCall 方法调用的示例:
示例:prepareCall 方法
// The following is new in JDBC 20
CallableStatement cs2 = connprepareCall(" = CALL ADDEMPLOYEE(, , )",
ResultSetTYPE_SCROLL_INSENSITIVE, ResultSetCONCUR_UPDATEABLE);
// New in JDBC 30
CallableStatement cs3 = connprepareCall(" = CALL ADDEMPLOYEE(, , )",
ResultSetTYPE_SCROLL_INSENSITIVE, ResultSetCONCUR_UPDATEABLE,
ResultSetHOLD_CURSOR_OVER_COMMIT);
处理参数
如前所述,CallableStatement 对象可以接收三种类型的参数:
IN
处理 IN 参数的方式与 PreparedStatement 相同。使用所继承的 PreparedStatement 类的各种设置方法来设置参数。
OUT
OUT 参数是使用 registerOutParameter 方法处理的。registerOutParameter 的最常见形式是接收索引参数作为第一个参数,并接收 SQL 类型作为第二个参数。这告诉 JDBC 驱动程序在处理语句时期望从参数得到什么样的数据。可以在 javasql 包 Javadoc 中找到 registerOutParameter 方法的其它两个变体。
INOUT
INOUT 参数要求完成 IN 参数和 OUT 参数的工作。对于每个 INOUT 参数,在可以处理语句之前,必须调用设置方法和 registerOutParameter 方法。如果不设置或注册任何参数,则处理语句时将抛出 SQLException。
有关更多信息,请参考示例:创建带有输入和输出参数的过程。
对于 PreparedStatement,除非再次调用设置方法,否则 CallableStatement 参数值在两次处理之间保持不变。clearParameters 方法不影响为输出注册的参数。在调用 clearParameters 之后,必须再次将所有 IN 参数设置为一个值,但所有 OUT 参数都不必再次注册。
注意:一定不能将参数的概念与参数标记的索引混淆。存储过程调用期望将特定数目个参数传送给它。特定 SQL 语句使用 字符(参数标记)来表示在运行时提供的值。请考虑以下示例来领会两个概念之间的差异:
CallableStatement cs = conprepareCall("CALL PROC(, "SECOND", )");
cssetString(1, "First"); //Parameter marker 1, Stored procedure parm 1
cssetString(2, "Third"); //Parameter marker 2, Stored procedure parm 3
通过名称访问存储过程参数
存储过程的参数具有相关联的名称,如以下存储过程声明所示:
示例:存储过程参数
注意:请阅读代码示例不保证声明以了解重要的法律信息。
CREATE
PROCEDURE MYLIBRARYAPROC
(IN PARM1 INTEGER)
LANGUAGE SQL SPECIFIC MYLIBRARYAPROC
BODY: BEGIN
<Perform a task here>
END BODY
存在一个名为 PARM1 的整数参数。在 JDBC 30 中,支持通过名称以及通过索引来指定存储过程参数。为此过程设置 CallableStatement 的代码如下:
CallableStatement cs = conprepareCall("CALL APROC()");
cssetString("PARM1", 6); //Sets input parameter at index 1 (PARM1) to 6
preparestatement是一种预编译的SQL语句,它可以提高数据库查询的性能。它可以防止SQL注入攻击,因为它只允许使用参数化查询。
与x的区别是,x是一种普通的SQL语句,它没有参数化查询的功能,也不能防止SQL注入攻击,而preparestatement可以提供这些功能。
好像是这个方法 getParameterMetaData ParameterMetaData getParameterMetaData() throws SQLException检索此 PreparedStatement 对象的参数的编号、类型和属性。返回:一个 ParameterMetaData 对象,它包含有关此 PreparedStatement 对象的参数的编号、类型和属性的信息抛出:SQLException - 如果发生数据库访问错误不过还是不明白,"select from table where field= and field=" 我想设置的参数应该是通过函数参数传递过来,
sschrodinger
2019/07/17
一个分布式系统 不可能同时满足 一致性( C:Consistency ),可用性( A: Availability )和分区容错性( P:Partition tolerance )这三个基本需求, 最多只能同时满足其中的 2 个 。
如下:
BASE 是 Basically Available (基本可用) ,Soft state (软状态),和 Eventually consistent (最终一致性)三个短语的缩写。
既是无法做到 强一致性 ( Strong consistency ),但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到 最终一致性 ( Eventual consistency )
基本可用
允许出现响应时间损失或者功能损失。
软状态
允许系统中的数据存在中间状态,并认为该状态不影响系统的整体可用性,即 允许系统在多个不同节点的数据副本存在数据延时 。
最终一致性
系统能够保证 在没有其他新的更新 *** 作 的情况下,数据最终一定能够达到一致的状态,因此所有客户端对系统的数据访问 最终都能够获取到最新的值 。
在分布式系统中,会有多个机器节点,因此需要一个 “ 协调者 ” ,而各个节点就是 “ 参与者 ”,协调者统一调度所有分布式节点的执行逻辑,这些被调度的分布式节点就是 “参与者”。
阶段一
阶段一主要是询问参与者是否可以进行提交。
阶段二
阶段二会根据阶段一的投票结果执行两种 *** 作: 执行事务提交 , 回滚事务 。
执行事务提交步骤如下:
中断事务步骤如下:
优点
原理简单,实现方便
缺点
同步阻塞,单点问题,数据不一致,过于保守
2PC (两阶段提交协议)
三阶段提交协议在协调者和参与者中都引入 超时机制 ,并且把两阶段提交协议的第一个阶段拆分成了两步:询问,然后再锁资源,最后真正提交。
协调流程如下:
阶段一: CanCommit
阶段二:preCommit
协调者在得到所有参与者的响应之后,会根据结果执行2种 *** 作:执行 事务预提交 ,或者 中断事务 。
执行事务预提交分为 3 个步骤:
中断事务也分为2个步骤:
阶段三:doCommit
该阶段做真正的提交,同样也会出现两种情况:
执行提交
中断事务
假设有任何参与者反馈了 no 响应,或者超时了,就中断事务。
优点
缺点
如果参与者收到了 preCommit 消息后,出现了网络分区,那么参与者等待超时后,都会进行事务的提交,这必然会出现事务不一致的问题
3PC(三阶段提交协议)
paxos 算法保证了一致性 。
在一个分布式系统中,有一组的 process,每个 process 都可以提出一个 value,consensus 算法就是用来从这些 values 里选定一个最终 value。如果没有 value 被提出来,那么就没有 value 被选中;如果有1个 value 被选中,那么所有的 process 都应该被通知到。
在 2PC 或者 3PC 中,如果协调者宕机了,整个系统就宕机了,这个时候就需要引用多个协调者,paxos 就是用来协调协调者的协议。
首先将议员的角色分为 proposers , acceptors ,和 learners (允许身兼数职)。 proposers 提出提案,提案信息包括提案编号和提议的 value ; acceptor 收到提案后可以接受( accept )提案,若提案获得多数派( majority )的 acceptors 的接受,则称该提案被批准( chosen ); learners 只能“学习”被批准的提案。划分角色后,就可以更精确的定义问题:
通过不断加强上述3个约束(主要是第二个)获得了 Paxos 算法。
批准 value 的过程中,首先 proposers 将 value 发送给 acceptors ,之后 acceptors 对 value 进行接受( accept )。为了满足只批准一个 value 的约束,要求经“多数派( majority )”接受的 value 成为正式的决议(称为“批准”决议)。这是因为无论是按照人数还是按照权重划分,两组“多数派”至少有一个公共的 acceptor ,如果每个 acceptor 只能接受一个 value ,约束 2 就能保证。
于是产生了一个显而易见的新约束:
注意 P1 是不完备的。 如果恰好一半 acceptor 接受的提案具有 value A ,另一半接受的提案具有 value B ,那么就无法形成多数派 ,无法批准任何一个 value 。
约束 2 并不要求只批准一个提案 ,暗示可能存在多个提案。 只要提案的 value 是一样的,批准多个提案不违背约束 2 。于是可以产生约束 P2:
如果 P1 和 P2 都能够保证,那么约束 2 就能够保证。
批准一个 value 意味着多个 acceptor 接受( accept )了该 value 。因此,可以对 P2 进行加强:
由于通信是异步的,P2a 和 P1 会发生冲突。如果一个 value 被批准后,一个 proposer 和一个 acceptor 从休眠中苏醒,前者提出一个具有新的 value 的提案。根据 P1,后者应当接受,根据 P2a,则不应当接受,这种场景下 P2a 和 P1 有矛盾。于是需要换个思路,转而对 proposer 的行为进行约束:
由于 acceptor 能接受的提案都必须由 proposer 提出,所以 P2b 蕴涵了 P2a,是一个更强的约束。
但是根据 P2b 难以提出实现手段。因此需要进一步加强 P2b。
假设一个编号为 m 的 value v 已经获得批准( chosen ),来看看在什么情况下对任何编号为 n ( n > m )的提案都含有 value v 。因为 m 已经获得批准( chosen ),显然存在一个 acceptors 的多数派 C ,他们都接受( accept )了 v 。考虑到任何多数派都和 C 具有至少一个公共成员,可以找到一个蕴涵 P2b 的约束 P2c:
如果一个没有 chose 过任何 proposer 提案的 acceptor 在 prepare 过程中接受了一个 proposer 针对提案 n 的问题,但是在开始对 n 进行投票前,又接受( accept )了编号小于n的另一个提案(例如 n-1 ),如果 n-1 和 n 具有不同的 value ,这个投票就会违背 P2c。因此在 prepare 过程中, acceptor 进行的回答同时也应包含承诺:不会再接受( accept )编号小于 n 的提案。这是对 P1 的加强:
通过一个决议分为两个阶段:
prepare 阶段
proposer 选择一个提案编号 n 并将 prepare 请求发送给 acceptors 中的一个多数派;
acceptor 收到 prepare 消息后,如果提案的编号大于它已经回复的所有 prepare 消息(回复消息表示接受 accept ),则 acceptor 将自己上次接受的提案回复给 proposer ,并承诺不再回复小于 n 的提案;
批准阶段
当一个 proposer 收到了多数 acceptors 对 prepare 的回复后,就进入批准阶段。 它要向回复 prepare 请求的 acceptors 发送 accept 请求,包括编号 n 和根据 P2c 决定的 value (如果根据 P2c 没有已经接受的 value ,那么它可以自由决定 value ) 。
在不违背自己向其他 proposer 的承诺的前提下, acceptor 收到 accept 请求后即批准这个请求。
这个过程在任何时候中断都可以保证正确性。例如如果一个 proposer 发现已经有其他 proposers 提出了编号更高的提案,则有必要中断这个过程。因此为了优化,在上述 prepare 过程中,如果一个 acceptor 发现存在一个更高编号的提案,则需要通知 proposer ,提醒其中断这次提案。
一个实例如下:
在这之后,提议者还需要做一件事,就是告知D,E,被决定的决议已经是什么了。即可。
这个过程叫 Learn 。 D , E 被称为 Learner
Paxos VS Zab
wiki 百科
维基百科-paxos
对于 paxos 来说,每一个议案都要经过不同节点的提出,并且讨论,在提出一个议案的阶段,另外的提议会被否决,导致了性能的低下。
ZAB 协议是为分布式协调服务 Zookeeper 专门设计的一种支持 崩溃恢复 和 原子广播 协议。
基于该协议, Zookeeper 实现了一种 主备模式 的系统架构来保持集群中各个副本之间数据一致性。具体如下图所示:
即只有一个 proposal 可以提出提议,其他的进程都只能复制决议。
所有客户端写入数据都是写入到 主进程(称为 Leader )中,然后,由 Leader 复制到备份进程(称为 Follower )中。从而保证数据一致性。
ZAB 协议的消息广播过程使用的是一个原子广播协议,类似一个 二阶段提交过程 。但是只需要 Follower 有一半以上返回 Ack 信息就可以执行提交,大大减小了同步阻塞。也提高了可用性。
对于客户端发送的写请求,全部由 Leader 接收, Leader 将请求封装成一个事务 Proposal ,将其发送给所有 Follwer ,然后,根据所有 Follwer 的反馈,如果超过半数成功响应,则执行 commit *** 作(先提交自己,再发送 commit 给所有 Follwer )。
流程如下:
Leader 挂了之后, ZAB 协议就自动进入崩溃恢复模式,选举出新的 Leader ,并完成数据同步,然后退出崩溃恢复模式进入消息广播模式。
可能 Leader 遇到如下异常情况:
第一种情况 主要是当 leader 收到合法数量 follower 的 ACKs 后,就向各个 follower 广播 COMMIT 命令,同时也会在本地执行 COMMIT 并向连接的客户端返回「成功」。 但是如果在各个 follower 在收到 COMMIT 命令前 leader 就挂了,导致剩下的服务器并没有执行都这条消息。
为了实现已经被处理的消息不能丢这个目的,Zab 的恢复模式使用了以下的策略:
第二种情况 主要是当 leader 接收到消息请求生成 proposal 后就挂了,其他 follower 并没有收到此 proposal ,因此经过恢复模式重新选了 leader 后,这条消息是被跳过的( 其他机器日志中没有这一条记录,但是他的日志中有这一条记录 )。 此时,之前挂了的 leader 重新启动并注册成了 follower ,他保留了被跳过消息的 proposal 状态,与整个系统的状态是不一致的, 需要将其删除 。
Zab 通过巧妙的设计 zxid 来实现这一目的。一个 zxid 是 64 位,高 32 是纪元( epoch )编号,每经过一次 leader 选举产生一个新的 leader ,新 leader 会将 epoch + 1 。低 32 位是消息计数器,每接到一个消息,则 $lo^{32} + 1$ ,新 leader 选举后这个值重置为 0。这样设计的好处是旧的 leader 挂了后重启,它不会被选举为 leader ,因为此时它的 zxid 肯定小于当前的新 leader 。当旧的 leader 作为 follower 接入新的 leader 后,新的 leader 会让它将所有的拥有旧的 epoch 未被 COMMIT 的 proposal 清除。
Zookeeper系列(5)--ZAB协议,消息广播,崩溃恢复,数据同步
Raft是用于管理复制日志的一致性算法,raft 协议也是一个 主备模型 ,有一个唯一的 leader 控制任务的提交。
如下是一个 raft 协议中每一个节点可能存在的状态,主要分为 领袖 、 群众 和 候选人 。
raft 最关键的一个概念是任期,每一个 leader 都有自己的任期,必须在任期内发送心跳信息给 follower 来延长自己的任期。
Raft 协议强依赖 Leader 节点的可用性来确保集群数据的一致性 。 数据的流向只能从 Leader 节点向 Follower 节点转移 。当 Client 向集群 Leader 节点提交数据后, Leader 节点接收到的数据处于 未提交状态( Uncommitted ) ,接着 Leader 节点会 并发向所有 Follower 节点复制数据 并等待接收响应,确保 至少集群中超过半数节点 已接收到数据后再向 Client 确认数据已接收。一旦向 Client 发出数据接收 Ack 响应后,表明此时数据状态进入已提交( Committed ), Leader 节点再向 Follower 节点发通知告知该数据状态已提交。
在数据同步阶段,可能出现七种情况:
动画演示 raft 算法
动画演示 raft 算法 - 2
Raft Vs zab
NWR 是一种在分布式存储系统中用于控制一致性级别的一种策略。在 Amazon 的 Dynamo 云存储系统中,就应用 NWR 来控制一致性。
让我们先来看看这三个字母的含义:
在分布式系统中, 数据的单点是不允许存在的 。即线上正常存在的 Replica 数量是 1 的情况是非常危险的,因为一旦这个 Replica 再次错误,就 可能发生数据的永久性错误。假如我们把 N 设置成为 2,那么,只要有一个存储节点发生损坏,就会有单点的存在。所以 N 必须大于 2。N约高,系统的维护和整体 成本就越高。工业界通常把 N 设置为3。
当 W 是 2、R 是 2 的时候, W+R>N ,这种情况对于客户端就是强一致性的。
在具体实现系统时,仅仅依靠 NWR 协议还不能完成一致性保证,因为在上述过程中,当读取到多个备份数据时,需要判断哪些数据是最新的,如何判断数据的新旧?这需要向量时钟来配合,所以对于 Dynamo 来说,是通过NWR协议结合向量时钟来共同完成一致性保证的。
mysql preparedstatement 查询_jsp实现数据库查询,prepareStatement()参数设置; 原创
2021-02-01 18:08:57
定投君
码龄4年
关注
我想传递一个参数,用该参数实现一个数据库的查询,但是报错:No value specified for parameter 1
java代码
public ListfindAll(int b) {
Listl=new ArrayList();
try{
Connection conn =getConnection();
String sql ="select from studentinfo where studentid=";
PreparedStatement ps = connprepareStatement(sql);
以上就是关于DELPHI基础教程:SQL编程(一)[4]全部的内容,包括:DELPHI基础教程:SQL编程(一)[4]、请高手解释一下,这个存储过程,谢谢!、preparestatement的用法和x的区别等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)