原标题:Spring认证中国教育管理中心-SpringDataCouchbase教程一(Spring中国教育管理中心)SpringDataCouchbase教程一1.1安装所有版本production两个都是分布在MavenCentral和Spring发布存储库中。因此,可以像任何其他Maven依赖项一样包含该库:示例1.通过Mavenorg.springframework.dataspring-data-couchbase包含依赖项4.2.5这将引入几个依赖项,包括底层CouchbaseJavaSDK、通常的Spring依赖项以及作为JSON映射基础结构的Jackson。您还可以从Spring快照存储库(https://repo.spring.io/libs-s...)和Spring里程碑存储库(https://repo.spring.io/libs-m...)以获得里程碑版本。这是一个关于如何使用当前SNAPSHOT依赖项的示例:示例2.使用快照版本org.springframework.dataspring-data-couchbase4.3.0-SNAPSHOTspring-libs-snapshotSpringSnapshotRepositoryhttps://repo.spring.io/libs-s...一旦你在类路径上拥有所有必需的依赖项,你就可以开始配置它了。仅支持Java配置(XML配置在4.0中被移除)。1.2.基于注解的配置(“JavaConfig”)要开始,您需要做的就是继承AbstractCouchbaseConfiguration并实现抽象方法。示例3.扩展AbstractCouchbaseConfiguration@ConfigurationpublicclassConfigextendsAbstractCouchbaseConfiguration{@OverridepublicStringgetConnectionString(){return"couchbase://127.0.0.1";}@OverridepublicStringgetUserName(){return"Administrator";}@OverridepublicStringgetPassword(){return"password";}@OverridepublicStringgetBucketName(){return"travel-sample";}}SpringDataCouchbase教程连接字符串由主机列表和可选方案(couchbase://)组成,例如上面显示的代码。您只需要提供要定向到的Couchbase节点列表(由,分隔)。需要注意的是,开发中一台主机就足够了,这里建议增加3到5个启动节点。Couchbase将自动从集群中获取所有节点,但您提供的唯一节点可能会在启动您的应用程序时出现问题。用户名和密码是通过RBAC(基于角色的访问控制)在CouchbaseServer集群中配置的。bucketName反映了您要使用的配置存储桶。此外,可以通过覆盖返回配置的configureEnvironment方法来调整SDK环境。来自ClusterEnvironment.BuilderClusterEnvironment的更多内容可以作为自定义bean(例如存储库、验证和自定义转换器)从该配置中自定义和覆盖。如果您使用SyncGateway和CouchbaseMobile,您可能会遇到前缀为_的字段的问题。这可能会有问题,因为默认情况下SpringDataCouchbase将类型信息存储为_class属性。覆盖typeKey()(例如返回MappingCouchbaseConverter.TYPEKEY_SYNCGATEWAY_COMPATIBLE)以更改所述属性的名称。如果启动应用程序,您应该会在日志中看到CouchbaseINFO级别的日志记录,表明底层CouchbaseJavaSDK正在连接到数据库。如果报告任何错误,请确保提供的凭据和主机信息正确无误。实体建模本章介绍如何对实体建模并解释它们在Couchbase服务器本身中的相应??表示。2.1对象映射基础本节涵盖了SpringData对象映射、对象创建、字段和属性访问、可变性和不可变性的基础知识。请注意,本节仅适用于不对底层数据存储(例如JPA)使用对象映射的SpringData模块。还请务必查阅特定于存储的对象映射的存储特定部分,例如索引、自定义列或字段名称等。SpringData对象映射的核心职责是创建域对象的实例和映射存储本机数据结构到这些实例上。这意味着我们需要两个基本步骤:使用公开的构造函数之一创建一个实例。该实例被填充以实现所有暴露的属性。2.1.1对象创建SpringData自动尝试检测持久实体的构造函数以用于实现该类型的对象。解析算法的工作原理如下:如果只有一个构造函数,则使用它。如果有多个构造函数,并且恰好有一个用@PersistenceConstructor注释,则使用它。如果有无参数构造函数,则使用它。其他构造函数将被忽略。值解析假定构造函数参数名称与实体的属性名称相匹配,即解析将像要填充属性一样执行,包括映射中的任何自定义(不同的数据存储列或字段名称等)。这还需要类文件中可用的参数名称信息或构造函数中存在的@ConstructorProperties注释。可以使用SpringFramework的@Valuevalue注释使用特定于商店的SpEL表达式来自定义值解析。内部对象创建为了避免反射的开销,SpringData对象创建默认使用运行时生成的工厂类,会直接调用领域类的构造函数。即对于此示例类型:classPerson{Person(Stringfirstname,Stringlastname){...}}我们将在运行时创建一个语义等同于此的工厂类:classPersonObjectInstantiatorimplementsObjectInstantiator{ObjectnewInstance(Object...args){returnnewPerson((String)args[0],(String)args[1]);}}与反射相比,这给了我们大约10%的性能提升。对于有资格进行此类优化的域类,它需要遵守一组约束:它不能是私有类它不能是非静态内部类它不能是SpringData使用的CGLib代理类构造函数不能是私有的如果这些条件之一匹配,SpringData将通过反射回退到实体实例化。2.1.2.属性填充一旦创建了实体的实例,SpringData就会填充该类的所有剩余持久属性。除非已经由实体的构造函数填充(即通过其构造函数参数列表使用),否则将首先填充标识符属性以允许解析循环对象引用。之后,在实体实例上设置构造函数未填充的任何非瞬态属性。为此,我们使用以下算法:如果属性不可变但公开了一个with...方法(见下文),我们使用该with...方法创建一个具有新属性值的新实体实例。如果定义了属性访问(即通过getter和setter),我们将调用setter方法。如果属性是可变的,我们直接设置字段。如果属性是不可变的,我们使用持久性操作使用的构造函数创建实例的副本(请参阅对象创建)。默认情况下,我们直接设置字段值。Propertypopulationinternals类似于我们在对象构造中的优化,我们还使用SpringData运行时生成的访问器类来与实体实例进行交互。类人{privatefinalLongid;私有字符串名字;private@AccessType(Type.PROPERTY)Stringlastname;Person(){this.id=null;}Person(Longid,Stringfirstname,Stringlastname){//字段赋值}PersonwithId(Longid){returnnewPerson(id,this.firstname,this.lastame);}voidsetLastname(Stringlastname){this.lastname=lastname;}}示例4.生成的属性访问器classPersonPropertyAccessorimplementsPersistentPropertyAccessor{privatestaticfinalMethodHandlefirstname;私人Person人;publicvoidsetProperty(PersistentPropertyproperty,Objectvalue){Stringname=property.getName();if("firstname".equals(name)){firstname.invoke(person,(String)value);}elseif("id".equals(name)){this.person=person.withId((Long)value);}elseif("lastname".equals(name)){this.person.setLastname((String)value);}}}PropertyAccessor持有底层对象的可变实例。这是为了启用其他不可变属性的突变。默认情况下,SpringData使用字段访问来读取和写入属性值。MethodHandles用于根据私有字段的可见性规则与字段进行交互。此类公开了一个withId(...)方法来设置标识符,例如在将实例插入数据存储并生成标识符时。调用withId(...)创建一个新的Person对象。所有后续突变都将发生在新实例中,而前一个实例保持不变。使用属性访问允许在不使用MethodHandles的情况下直接调用方法。与反射相比,这使我们的性能提高了大约25%。对于符合此类优化条件的域类,它需要遵守一组约束:类型不得位于默认或java包下。类型及其构造函数必须是公共的,因为内部类的类型必须是静态的。使用的Java运行时必须允许原始的ClassLoader。Java9及更高版本施加了某些限制。默认情况下,SpringData尝试使用生成的属性访问器,如果检测到限制,则回退到基于反射的访问器。让我们看一下下面的实体:示例5.示例实体类Person{privatefinal@IdLongid;privatefinalString名字,姓氏;私人最终LocalDate生日;私人最终年龄;私人字符串评论;private@AccessType(Type.PROPERTY)String备注;staticPersonof(Stringfirstname,Stringlastname,LocalDatebirthday){returnnewPerson(null,firstname,lastname,birthday,Period.between(birthday,LocalDate.now()).getYears());}Person(Longid,Stringfirstname,Stringlastname,LocalDatebirthday,intage){this.id=id;this.firstname=firstname;this.lastname=lastname;this.birthday=birthday;this.age=age;}PersonwithId(长id){returnnewPerson(id,this.firstname,this.lastname,this.birthday,this.age);}voidsetRemarks(Stringremarks){this.re标记=备注;}}SpringDataCouchbase教程一个Identifier属性是final的,但是在构造函数中设置了null。该类暴露了一个withId(...)方法,用于设置标识符,例如,在将实例插入数据时存储和生成标识符时。创建Person的新实例时,原始实例保持不变。相同的模式通常适用于存储管理,但可能必须更改其他属性以实现持久性操作。Wither方法是可选的,因为持久性构造函数(参见图6)实际上是一个复制构造函数,设置属性将被转换为创建一个应用了新标识符值的新实例。firstname和lastname属性是普通的不可变属性,可以通过getter公开。age属性是不可变的,但派生自birthday。使用所示设计,数据库值将胜过默认值,因为SpringData仅使用声明的构造函数。尽管意图是首选计算,但重要的是此构造函数也将其年龄作为参数(它可能会被忽略),否则属性填充步骤将尝试设置年龄字段并失败,因为它是不可变的并且没有with...方法present。comment属性是可变的,并通过直接设置其字段来填充。remarks属性是可变的,可以通过直接设置注释字段或通过调用类的setter方法来填充。该类公开了用于创建对象的工厂方法和构造函数。这里的核心思想是使用工厂方法而不是额外的构造函数来避免通过@PersistenceConstructor构造函数。相反,属性的默认设置是在工厂方法中处理的。