Can I still access a sitecore contact facet once session is flushed?

I'm hoping I've not gotten the wrong end of the stick here (as always the sitecore documentation is woeful!)

I wanted a way to store information against a visitor, I'm reasonably new to sitecore, but the contact facets seemed the idealsolution, pretty much implemented word for word from the link above, until it hit production I was quite pleased with it. When I stored information it persisted, I could read it:

public IMpmVisitorFacet GetMpmVisitorFacet()
    return _contact.GetFacet<IMpmVisitorFacet>(_MPMVisitorConfigName);

and set info and everything seemed great. I could also see the sitecore SC_ANALYTICS_GLOBAL_COOKIE being set, everything seemed wonderful. Then I did some more thorough tests...

The problem appears to be that the data just doesn't persist for long. If I put some info into the facet it will hang around for an hour or so (I can close my browser, look at other, sites, etc. etc.) and I'll be able to access it but after an "amount of time" it just all goes away.

Having revisited the docs (have I mentioned that they're not very good) I noticed a caveat in a sentence that I didn't see before:

Well, I can create another web form page that only reads the employee number. That will show me that the contact facet data is being stored in memory at least. But what about permanent storage?

Hold on, I thought this was permanent storage?! So the example shows some code to read the "facet".

var contact = Tracker.Current.Contact;
var data = contact.GetFacet<IEmployeeData>("Employee Data");
data.EmployeeId = "ABC123";
<p>Employee data contact facet updated.</p>
<p>Contact ID: <b><%=contact.ContactId.ToString()%></b></p>
<p>Employee #: <b><%=data.EmployeeId%></b></p>

But this facet seems to only exist for a short period of time. It then goes on:

For performance reasons Sitecore only writes contact data to xDB when the session ends.This means that if I look in MongoDB...

it then goes on to show the data in it's new shiny trendy mongoDb implementation. But what use is it in mongo if I can't actually access and use that information programatically!

So this raises the question how do I access this contact information once the session is abandoned?

i.e. user logs into my site -> I add some information into their contact facet -> they come back the next day -> I want to read the information I added previously

There are several other docs which talk about accessing this data in the experience profile, to index into Lucene and in the Experience platform(why have two products with almost the exactly same name?!) but nothing to say how to access this information in the web site itself, in code.

To add to the comments by Dmytro Shevchenko:

  • I can see my a user in the "experience profile" and I can see my visits to the site.
  • I know this user did have my additional facet information because it triggered some code.
  • I can find my user (from the id's taken out of the query string in the experience profile page) in the mongo Db
  • But when I look at the user in mongoDb the additional information is not there.
  • some of the contact records have this data but others don't

So it appears to be an issue with writing the new information to mongo...Does anyone have any help or similar experience of this?


After a great deal of debugging, fiddling and testing I finally figured this out. My issue, it turned out, wasn't the writing to mongo it was in the reading back out of mongo once it had been written.

The sitecore documentation seems (as usual) to completely miss a rather fundamental part of the working of this. About a third of the way down the docs it states:

public EmployeeData()

The "EnsureAttribute" method is the equivalent of declaring a value-type variable.

Ok, this is very misleading. What this EnsureAttribute appears to do is load the data for the facet into the current class from mongo. If you don't do this for every property in your facet then it does not set the value from the mongoDb! This was my mistake, I hadn't "ensured" every property in the class.

So what was happening is,

  • I put my data into the facet
  • the facet data persists in the Session and I can see, access it change it,etc.
  • The data is eventually flushed to mongo (xDb if you must)
  • the user returns, the system recognises them correctly (there is no need to identify the user, the SC_ANALYTICS_GLOBAL_COOKIE does this for you)
  • But it does not load the data (out of mongo and back into the session) unless you "ensure" it.

So the EnsureAttribute does not "declare a value type" (this is just totally wrong in my opinion) it loads the data out of mongodb and into the current Session.

I think the step you might be missing here is the Tracker.Current.Session.Identify() method to identify a known contact. The data in the Tracker api only lasts for the current session and you need to load the contact into the session.

The implementation of xDB relies on a contact identifying themselves when they visit the site, by logging in or registering for example.

Once they have logged in you can use a unique identifier e.g email address and pass this to the identify method -Tracker.Current.Session.Identify("Email Address of the visitor").

Once you have called this method, if the user has identified themselves previously, the contact data will be loaded into the current session and any existing facet information will be available in the Tracker Api.

Your problem lays in regards how you pulling the contact: If you are in a page request, you should access the current contact via Tracker.Current.Contact. your code is not in a page request, but the user may have a live session, use the ContactManager with the methods described above. If the contact is not in a live session right now, you should use ContactRepository. See an example on how to use it here. Copied from https://sitecore.stackexchange.com/questions/3319/why-are-custom-xdb-facets-being-overwritten-on-session-end answered by Dmitry Shevchenko.

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

  • Sitecore和ASP.net MVC(Sitecore and ASP.net MVC)
    问题 我们正在启动一个以sitecore作为CMS的新项目。 我当时正在考虑将Sitecore用作内容创作工具,并与Sitecore一起在Content Delivery(CDA)方面使用ASP.net MVC。 很想听听您对此的想法和想法。 有人尝试过吗? Sitecore和MVC是竞争技术还是互补技术? 任何建筑构想都是值得欢迎的。 回答1 在某些情况下,将两者合并可能会带来巨大的好处。 MVC不太适合内容驱动的网站。 但是,具有结构化流程和多个数据表示形式的Web应用程序将从中受益匪浅。 当涉及到多个数据表示时,Sitecore具有一定的局限性-您只能在一个项目上定义一组设计详细信息。 如果您不需要所见即所得的编辑或简单的一键式预览,则可以将Sitecore用作数据存储库,并利用其管道中的某些Context值(例如语言)。 为了使这项工作正常,必须对Sitecore HTTP管道进行一些修改: 1)如果使用IIS6中的aspx扩展名来获取ASP.NET来处理MVC请求(例如/Controller.aspx/Action),请修复Sitecore的FilePath解析(Sitecore解析文件路径的方式会导致路径获取错误。切碎的)。 要解决此问题,请在httpRequestBegin管道的开始处放置一个新处理器。 public class MvcFixHttpProcessor
  • OAuth2.0令牌异常行为(无效凭据401)(OAuth2.0 token strange behaviour (Invalid Credentials 401))
    问题 通常,Google OAuth2.0机制运行良好。 用户确认有权访问具有选定范围的Google帐户。 检索刷新令牌并将其保存到长时间存储中。 每次需要时(如果访问令牌已过期),都会检索访问令牌并将其用于访问API。 但是有时(到目前为止,在超过6个月的时间内只有两次),我经历了奇怪的行为: 向Google API发出的请求返回无效凭据(401)错误。 刷新访问令牌(使用存储的刷新令牌)无济于事。 这是测试此问题时获得的一些结构化输出: + ------------------------------------------------------------------------- + | 1.TRYING TO REFRESH THE TOKEN. | | 2.DONE REFRESHING THE TOKEN. | + ------------------------------------------------------------------------- + | access: **************************************************** | | refresh: ********************************************* | | expires: 3600 | | created
  • 休眠:flush()和commit()(Hibernate: flush() and commit())
    问题 分别调用org.hibernate.Session.flush()是否是一种好习惯? 如org.hibernate.Session文档中所述, 在提交事务并关闭会话之前,必须在工作单元的末尾调用(取决于刷新模式,Transaction.commit()会调用此方法)。 如果org.hibernate.Transaction.commit()已经做到了,您能明确解释调用flush()的目的吗? 回答1 在《 Hibernate手册》中,您可以看到此示例 Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); for (int i = 0; i < 100000; i++) { Customer customer = new Customer(...); session.save(customer); if (i % 20 == 0) { // 20, same as the JDBC batch size // flush a batch of inserts and release memory: session.flush(); session.clear(); } } tx.commit(); session.close()
  • sqlalchemy flush()并获取ID?(sqlalchemy flush() and get inserted id?)
    问题 我想做这样的事情: f = Foo(bar='x') session.add(f) session.flush() # do additional queries using f.id before commit() print f.id # should be not None session.commit() 但是当我尝试f.id时,它是None 。 我怎样才能使它正常工作? 回答1 您的示例代码应该已经按原样工作。 SQLAlchemy应该为f.id提供一个值,假设它是自动生成的主键列。 主键属性在生成时立即在flush()进程中填充,并且不需要调用commit() 。 因此,这里的答案在于以下一项或多项: 映射的详细信息如果使用的后端有任何奇怪现象(例如,SQLite不会为复合主键生成整数值) 打开echo时发出的SQL表示什么 回答2 我遇到了同样的问题,经过测试,我发现这些答案中没有一个是足够的。 当前,或者从sqlalchemy .6+开始,有一个非常简单的解决方案(我不知道它是否存在于以前的版本中,尽管我认为确实存在): session.refresh() 因此,您的代码将如下所示: f = Foo(bar=x) session.add(f) session.flush() # At this point, the object f has been
  • Sitecore:以编程方式将工作流程分配给项目(Sitecore: Assign workflow to an item programmatically)
    问题 我已经配置了工作流程,像往常一样以“草稿”状态开始。 我已经为模板的标准值配置了工作流程。 它在内容编辑器中完美运行。 (当我使用内容编辑器创建项目时,一旦创建项目,工作流就会分配给该项目,并且其状态变为“草稿”。) 但是,当我在上述模板下以编程方式创建项目时,它不会分配工作流程。 我应该怎么做才能分配工作流程? 如果有的话,请共享任何代码示例。 谢谢。 Sitecore.Data.Items.TemplateItem template = this.MasterDatabase.GetItem("/sitecore/templates/user defined/sample types"); Sitecore.Data.Items.Item parent = this.MasterDatabase.GetItem(parentId); Sitecore.Data.Items.Item newItem; // Create new item and retrieve it newItem = template.CreateItemFrom("sampleName", parent); newItem.Editing.BeginEdit(); newItem.Name = StringFormatter.CreateItemNameFromID(this.newItem)
  • 休眠openSession()vs getCurrentSession()(Hibernate openSession() vs getCurrentSession())
    问题 我对在JSP Web应用程序中使用Hibernate有一些疑问。 hibernate.current_session_context_class的值应该是多少? 然后,应使用以下哪个语句? 又为什么呢? Session s = HibernateUtil.getSessionFactory().openSession(); Session s = HibernateUtil.getSessionFactory().getCurrentSession() 最后,“每个Web应用一个会话”或“每个请求一个会话”哪个更好? 回答1 如本论坛帖子中所述,1和2是相关的。 如果将hibernate.current_session_context_class设置为thread,然后实现类似于servlet过滤器的功能来打开会话,则可以使用SessionFactory.getCurrentSession()在其他任何地方访问该会话。 SessionFactory.openSession()总是打开一个新会话,您必须在完成操作后关闭它。 SessionFactory.getCurrentSession()返回绑定到上下文的会话-您无需关闭它。 如果您使用Spring或EJB管理事务,则可以将它们配置为与事务一起打开/关闭会话。 one session per web app绝对不要使用one
  • How to limit Sitecore Language Write to only certain parts of the content tree
    In our Sitecore implementation, we have branch editors who will need language write access to both English and their native language (e.g. German). However, we have certain portions of our content tree where the English version should not be editable by those branch editors, but the native language version should. To give a specific example, if we have a product page that has some global information on it (e.g. a part number), and some localizable information on it (e.g. a description field), we're using field level security to lock down the global (part number) fields, but need a way to
  • 'System.Web.Webpages.Html.Htmlhelper' does not contain a definition for 'Sitecore'
    I'm getting this error in Visual Studio, when I use @Html.Sitecore: 'System.Web.Webpages.Html.Htmlhelper' does not contain a definition for 'Sitecore' and the best extension methods overload 'Sitecore.Mvc.HtmlHelperExtensions.Sitecore(System.Web.Mvc.HtmlHelper)' has some invalid arguments.` However, once deployed it does run without any problems. I'm using Sitecore 7.2 with MVC 5.1. Articles that I've read that deal with similar error messages, talk about the system.web.webPages.razor section of the Views folder web.config file. This is how it appears in my solution. <system.web.webPages.razor
  • 微服务架构中的单点登录(Single Sign-On in Microservice Architecture)
    问题 我正在尝试设计一个绿地项目,该项目将具有多个服务(服务数据)和Web应用程序(服务HTML)。 我已经读过有关微服务的信息,它们看起来很合适。 我仍然存在的问题是如何实施SSO。 我希望用户进行一次身份验证,并有权访问所有不同的服务和应用程序。 我可以想到几种方法: 添加身份服务和应用程序。 任何具有受保护资源的服务都将与身份服务进行对话,以确保其拥有的凭据有效。 如果不是,它将重定向用户进行身份验证。 使用Web标准(例如OpenID),并让每个服务处理自己的身份。 这意味着用户将必须分别授权每个服务/应用程序,但之后将是SSO。 我很高兴听到其他想法。 如果特定的PaaS(例如Heroku)具有专有的解决方案,那也是可以接受的。 回答1 在我上一份工作中实现微服务架构时,我们认为最好的方法是与#1一致,即添加身份服务并授权通过它进行服务访问。 在我们的案例中,这是通过令牌完成的。 如果请求带有授权令牌,那么如果它是用户与服务会话中的第一个调用,我们可以通过身份服务验证该令牌。 令牌通过验证后,便会保存在会话中,因此用户会话中的后续调用不必进行其他呼叫。 如果需要在该会话中刷新令牌,则还可以创建计划的作业。 在这种情况下,我们正在使用OAuth 2.0端点进行身份验证,并且令牌已添加到HTTP标头中,用于对我们域的调用。 所有服务都是从该域路由的
  • Sitecore Glass Mapper always null
    I am using Sitecore Glass Mapper for a new project I'm setting up. We are using Sitecore 7.2, latest version of Team Development for Sitecore (TDS) code generation and the latest version of glass. The code I am trying to execute: var b = new SitecoreContext(); var c = b.GetCurrentItem<T01_Homepage>(); b is not null. c is null. var d = b.GetItem<T01_Homepage>("path") d is null. I added my assembly in GlassMapperScCustom: public static IConfigurationLoader[] GlassLoaders(){ var attributes = new AttributeConfigurationLoader(new[] { "Company.Framework.Websites.Corporate", "Company.Framework.Core"
  • How can I login programmatically into Sitecore?
    How can I login programmatically into Sitecore? For example if you would like to connect a small part of the Sitecore API to a desktop application, you would need to login into sitecore first to access the databases etc. Can this be done?
  • Sitecore: Assign workflow to an item programmatically
    I have configured a workflow, starts with "Draft" state as usual. And I have configured the workflow for standard values of the template. It works perfect in Content editor. (When I create an item using the content editor, once I create the item, Workflow gets assigned to the item and it's state becomes "Draft".) But when I create an item programmatically under the above template it does not assign the workflow. What should I do to assign workflow? Please share any code samples if you have. Thanks. Sitecore.Data.Items.TemplateItem template = this.MasterDatabase.GetItem("/sitecore/templates
  • 如何从Symfony2 config.yml中读取配置设置?(How do I read configuration settings from Symfony2 config.yml?)
    问题 我已经将设置添加到了config.yml文件中,如下所示: app.config: contact_email: somebody@gmail.com ... 对于我的一生,我无法弄清楚如何将其读入变量。 我在其中一个控制器中尝试过类似的操作: $recipient = $this->container->getParameter('contact_email'); 但是我收到一个错误消息: 必须定义参数“ contact_email”。 我已经清除了缓存,还查看了Symfony2重新加载的站点文档中的所有内容,但是找不到如何执行此操作。 可能现在太累了,无法解决这个问题。 有人能帮忙吗? 回答1 而不是在app.config定义contact_email ,而是在parameters条目中定义它: parameters: contact_email: somebody@gmail.com 您应该发现正在控制器内进行的呼叫现在可以正常工作了。 回答2 正如将在其他答案中提出的那样,虽然将contact_email移至parameters.yml的解决方案很简单,但是如果您处理许多包或处理嵌套的配置块,这很容易使参数文件混乱。 首先,我将严格回答这个问题。 稍后,我将提供一种从服务获取这些配置的方法,而无需通过公共空间作为参数。 第一种方法:分离的配置块,将其作为参数
  • 【MySQL】有关登录连接的几个参数(max_connections等)及其相关错误
    【MySQL】有关登录连接的几个参数(max_connections、max_user_connections、max_connect_errors、Max_used_connections等)及其相关错误 真题1、在登录MySQL时遇到“ERROR 1040 (00000): Too many connections”错误,如何解决?答案:该错误表示连接数过多,不能正常登录数据库。主要原因是max_connections参数设置过小,该参数表示允许客户端并发连接的最大数量,默认值是151,可以根据业务需求将该参数设置为500-2000,最小值为1,最大值为100000。需要注意的是,其实MySQL允许的最大连接数为:max_connections+1,因为这超出的一个用户其实是作为超级管理员来使用的。所以,若max_connections的值设置为1,则第3个客户端登录才会报“Too many connections”的错误。示例如下所示:mysql> show variables like '%max_connection%';+-----------------+-------+| Variable_name | Value |+-----------------+-------+| max_connections | 151 |+-----------------+----
  • org.hibernate.AssertionFailure:条目中的id为null(发生异常后不要刷新Session)(org.hibernate.AssertionFailure: null id in entry (don't flush the Session after an exception occurs))
    问题 我有一个休眠和JSF2应用程序要转到部署服务器,并突然抛出org.hibernate.AssertionFailure:异常中为null id。 我将立即提供堆栈跟踪和代码,但首先有四个重要问题: 这仅在部署服务器上运行(在Windows Sever 2008上运行Jboss和MySql。)在我的开发机器上(在Windoes 7 Pro上运行Tomcat和MySql)上没有发生,在暂存环境(在Linux上运行的Jboss和MySql上)也没有发生。 ) 对此进行研究,似乎人们在尝试插入对象时会收到此错误。 但是当我做一个简单的查询时,我得到了错误。 (实际上,各种不同的查询,因为错误随机出现在几页上。) 该错误只会偶尔出现。 如果我重新启动Jboss,它会消失,但会在一段时间后返回。 此外,它也不是一致的,在某些点击上是不一致的,在其他点击上不是一致的。 即使点击,当我对页面进行简单刷新时,它也会返回正常状态。 我正在使用c3p0(下面的配置) 知道发生了什么吗? 代码详细信息: 这发生在一个地址对象上。 这是完整的hbm: <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate
  • Oracle dblink介绍
    Oracle dblink介绍 官网:https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_5005.htm 当用户要跨本地数据库访问另外一个数据库表中的数据时,本地数据库中必须创建了远程数据库的 DBLINK, 通过 DBLINK 可以像访问本地数据库一样访问远程数据库表中的数据。 其实, DBLINK 和数据库中的 VIEW 差不多,创建 DBLINK 的时候需要知道待读取数据库的 IP 地址、 ORACLE_SID 以及数据库用户名和密码。 在创建DBLINK之前,普通用户必须具有相关的权限才能创建DBLINK,以SYS用户登录到本地数据库可以看到相关的权限: SELECT * FROM USER_SYS_PRIVS T WHERE T.PRIVILEGE LIKE UPPER('%LINK%'); SYS@PROD1> SELECT * FROM USER_SYS_PRIVS T WHERE T.PRIVILEGE LIKE UPPER('%LINK%');USERNAME PRIVILEGE ADM------------------------------ ---------------------------------------- ---SYS CREATE DATABASE LINK
  • 跟踪Java中的内存泄漏/垃圾回收问题(Tracking down a memory leak / garbage-collection issue in Java)
    问题 这是我几个月来一直在努力寻找的问题。 我有一个Java应用程序正在运行,该应用程序处理xml提要并将结果存储在数据库中。 存在间歇性的资源问题,很难追踪。 背景:在生产包装盒(问题最明显的地方)上,我对包装盒的访问不是特别好,并且无法使Jprofiler运行。 那个盒子是运行centos 5.2,tomcat6和java的64位四核8gb机器。 它以这些java-opts开头 JAVA_OPTS="-server -Xmx5g -Xms4g -Xss256k -XX:MaxPermSize=256m -XX:+PrintGCDetails - XX:+PrintGCTimeStamps -XX:+UseConcMarkSweepGC -XX:+PrintTenuringDistribution -XX:+UseParNewGC" 技术堆栈如下: Centos 64位5.2 Java 6u11 雄猫6 Spring / WebMVC 2.5 休眠3 石英1.6.1 DBCP 1.2.1 的MySQL 5.0.45 高速缓存1.5.0 (当然还有许多其他依赖项,尤其是jakarta-commons库) 我最能重现此问题的是内存要求较低的32位计算机。 我确实可以控制。 我已经用JProfiler对其进行了探究,并修复了许多性能问题(同步问题,预编译
  • 使用session_write_close()时的PHP Save Session;(PHP Save Session when using session_write_close();)
    问题 我有一页要进行长时间的民意调查,我必须在此页的开头使用 session_start(); session_write_close(); 因为 : 为了防止并发写入,任何时候在一个会话上都只能操作一个脚本 因此,如果我不这样做,并且长时间轮询正在运行,则用户将无法加载其他页面。 因此,可以从此轮询页面访问会话中的数据,但是在脚本的某个时刻,我必须将会话保存回服务器,因为我对此进行了一些更改。 怎么做呢? 那就太好了,这将是做某事的一种方式 session_write_open(); //do stuff session_write_close(); 但是session_write_open()不存在! 谢谢 回答1 在对会话进行更改之前,请再次调用session_start 。 进行更改,如果仍然不想退出,请再次调用session_write_close 。 您可以根据需要多次执行此操作。 回答2 先前的解决方案将创建一个会话ID和cookie ...我不会按原样使用它: 每次您调用session_start()时都会创建会话。 如果要避免使用多个cookie,请编写更好的代码。 多个session_start(),特别是对于同一脚本中的相同名称,似乎是个坏主意。 看到这里:https://bugs.php.net/bug.php?id=38104 我现在也在寻找一种解决方案
  • JPA:对大型结果集进行迭代的正确模式是什么?(JPA: what is the proper pattern for iterating over large result sets?)
    问题 假设我有一个包含数百万行的表。 使用JPA,迭代针对该表的查询的正确方法是什么,以至于我没有一个包含数百万个对象的内存列表? 例如,如果表很大,我怀疑以下内容会爆炸: List<Model> models = entityManager().createQuery("from Model m", Model.class).getResultList(); for (Model model : models) { System.out.println(model.getId()); } 分页(循环并手动更新setFirstResult() / setMaxResult() )真的是最好的解决方案吗? 编辑:我针对的主要用例是一种批处理作业。 如果需要很长时间才能运行就可以了。 没有涉及Web客户端。 我只需要为每一行“做某事”,一次一行(或一些小N)。 我只是想避免同时将它们全部存储在内存中。 回答1 Java Persistence with Hibernate的第537页提供了使用ScrollableResults的解决方案,但可惜它仅适用于Hibernate。 因此,似乎确实需要使用setFirstResult / setMaxResults和手动迭代。 这是我使用JPA的解决方案: private List<Model> getAllModelsIterable(int
  • 玩转Redis-老板带你深入理解分布式锁
    前言 公司交给了萌新小猿一个光荣而艰巨的项目,该项目需要使用分布式锁,这可难道了小猿,只是听说过分布式锁很牛掰,其他就一概不知了,唉不懂就问呗,遂向老板请教。 老板:我们每天不都在经历分布式锁吗,我来给你回忆回忆。 小猿:好勒,瓜子板凳已备好。 本文结构 为什么要使用分布式锁分布式锁有哪些特点分布式锁流行算法及其优缺点 基本算法relock算法token算法数据库排它锁、ZooKeeper分布式锁、Google的Chubby分布式锁 总结 1、为什么要使用分布式锁 这个问题应该拆分成以下2个问题回答。 1.1、为什么使用锁 保证在同一时刻共享资源只能被一个客户端访问; 根据锁用途分为以下两种: 共享资源只允许一个客户端操作;共享资源允许多个客户端操作; 1.1.1、仅允许一个客户端访问 共享资源的操作不具备幂等性。 常见于 数据的修改、删除操作; 在上面的例子中, 人物事件系统含义经理A-N多个线程码农小猿-调高空调温度非幂等共享资源秘书的允许获取锁 1.1.2、允许多个客户端操作 主要应用场景是:共享资源的操作具有幂等性; 如 数据的查询。 既然都具有幂等性了,为什么还需要分布式锁呢,通常是为了效率或性能,避免重复操作(尤其是消耗资源的操作)。例如我们常见的缓存方案。 在上面的例子中, 人物事件系统含义经理A-N多个线程码农小猿