精华内容
下载资源
问答
  • 方式:使用自动映射处理一对一映射 实体类改造 UserMapper接口增加接口方法 UserMapper.xml增加SQL 单元测试 方式二:使用resultMap配置一对一映射 UserMapper接口增加接口方法 UserMapper.xml增加SQL 单元测试 ...

    概述

    我们还是继续使用我们的RBAC权限系统来演示。

    假设在RBAC权限系统中,一个用户只能拥有一个角色。


    需求

    实现在查询用户信息的同时获取用户拥有的角色信息


    方式一:使用自动映射处理一对一映射

    实体类改造

    一个用户拥有一个角色,因此现在SysUser类中增加SysRole字段

    /**
     * 
     * 
     * @ClassName: SysUser
     * 
     * @Description: 用户表
     * 
     * @author: Mr.Yang
     * 
     * @date: 2018年4月13日 下午9:24:21
     */
    public class SysUser  {
    
    	//其他原有字段以及setter getter
    
    	/**
    	 * 用户角色
    	 */
    	private SysRole sysRole;
    	
    	// setter getter
    	public SysRole getSysRole() {
    		return sysRole;
    	}
    
    	public void setSysRole(SysRole sysRole) {
    		this.sysRole = sysRole;
    	}
    
    	
    }
    

    使用自动映射就是通过别名让MyBatis自动将值匹配到对应的子弹上,简单的别名映射如user_name 对应userName .

    除此之外MyBatis还支持复杂的属性映射,可以多层嵌套。 比如将role.role_name 映射到 role.roleName上。 MyBatis首先会查找role属性,如果存在role属性就创建role对象,然后在role对象中继续查找roleName, 将role_name的值绑定到role对象的roleName属性上 。


    UserMapper接口增加接口方法

    /**
    	 * 
    	 * 
    	 * @Title: selectSysUserAndSysRoleById
    	 * 
    	 * @Description: 根据Id查询用户信息的同时获取用户拥有的角色信息
    	 * 
    	 * @param id
    	 * @return
    	 * 
    	 * @return: SysUser
    	 */
    	SysUser selectSysUserAndSysRoleById(Long id);
    

    UserMapper.xml增加SQL

    <select id="selectSysUserAndSysRoleById" resultType="com.artisan.mybatis.xml.domain.SysUser">
    		SELECT
    			u.id,
    			u.user_name userName,
    			u.user_password userPassword,
    			u.user_email userEmail,
    			u.user_info userInfo,
    			u.create_time createTime,
    			u.head_img headImg,
    			r.id "sysRole.id",
    			r.role_name "sysRole.roleName",
    			r.enabled "sysRole.enabled",
    			r.create_by "sysRole.createBy",
    			r.create_time "sysRole.createTime"
    		FROM
    			sys_user u
    		INNER JOIN sys_user_role ur ON u.id = ur.user_id
    		INNER JOIN sys_role r ON ur.role_id = r.id
    		WHERE
    			u.id = #{id}
    	</select>
    

    注意上述SQL中 sys_role查询的列的别名都是 “sysRole.”前缀,这和SysUser实体类中SysRole属性的名称保持一致,通过这种方式将sysRole的属性都映射到了SysUser的sysRole属性上


    单元测试

    @Test
    	public void selectSysUserAndSysRoleByIdTest() {
    		logger.info("selectSysUserAndSysRoleByIdTest");
    		// 获取SqlSession
    		SqlSession sqlSession = getSqlSession();
    		try {
    			// 获取UserMapper接口
    			UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    			// 注意:数据库中id=1的用户拥有2个角色,不适合这个例子。
    			// 调用selectSysUserAndSysRoleById方法,查询id=1001的用户及其角色
    			SysUser sysUser = userMapper.selectSysUserAndSysRoleById(1001L);
    			// 期望用户不为空
    			Assert.assertNotNull(sysUser);
    			// 期望角色不为空
    			Assert.assertNotNull(sysUser.getSysRole());
    
    			logger.info(sysUser);
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			sqlSession.close();
    			logger.info("sqlSession close successfully ");
    		}
    	}
    

    debug调测下数据

    这里写图片描述


    日志

    2018-04-29 23:43:15,905  INFO [main] (BaseMapperTest.java:26) - sessionFactory bulit successfully
    2018-04-29 23:43:15,913  INFO [main] (BaseMapperTest.java:29) - reader close successfully
    2018-04-29 23:43:15,918  INFO [main] (UserMapperTest.java:1007) - selectSysUserAndSysRoleByIdTest
    2018-04-29 23:43:16,008 DEBUG [main] (BaseJdbcLogger.java:145) - ==>  Preparing: SELECT u.id, u.user_name userName, u.user_password userPassword, u.user_email userEmail, u.user_info userInfo, u.create_time createTime, u.head_img headImg, r.id "sysRole.id", r.role_name "sysRole.roleName", r.enabled "sysRole.enabled", r.create_by "sysRole.createBy", r.create_time "sysRole.createTime" FROM sys_user u INNER JOIN sys_user_role ur ON u.id = ur.user_id INNER JOIN sys_role r ON ur.role_id = r.id WHERE u.id = ? 
    2018-04-29 23:43:16,135 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: 1001(Long)
    2018-04-29 23:43:16,196 TRACE [main] (BaseJdbcLogger.java:151) - <==    Columns: id, userName, userPassword, userEmail, userInfo, createTime, headImg, sysRole.id, sysRole.roleName, sysRole.enabled, sysRole.createBy, sysRole.createTime
    2018-04-29 23:43:16,198 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1001, artisan, 123456, test@artisan.com, <<BLOB>>, 2018-04-13 21:12:47.0, <<BLOB>>, 2, 普通用户, 1, 1, 2018-04-13 21:12:46.0
    2018-04-29 23:43:16,215 DEBUG [main] (BaseJdbcLogger.java:145) - <==      Total: 1
    2018-04-29 23:43:16,216  INFO [main] (UserMapperTest.java:1021) - SysUser [id=1001, userName=artisan, userPassword=123456, userEmail=test@artisan.com, userInfo=测试用户, headImg=[18, 49, 35, 18, 48], createTime=Fri Apr 13 21:12:47 BOT 2018, sysRole=SysRole [id=2, roleName=普通用户, enabled=1, createBy=1, createTime=Fri Apr 13 21:12:46 BOT 2018, user=null, privilegeList=null]]
    2018-04-29 23:43:16,222  INFO [main] (UserMapperTest.java:1026) - sqlSession close successfully 
    
    
    

    通过SQL日志可以看到已经查询出的一条数据,MyBatis将这条数据映射到了两个类中,像这种通过一次查询将结果映射到不同对象的方式,称之为关联的嵌套结果查询。

    关联的嵌套结果映射需要关联多个表将所有需要的值一次性查询出来, 这种方式的好处是减少数据库的查询次数,减轻数据库的压力。 缺点是需要些很复杂的SQL,并且当嵌套结果更负载时,不容易一次写正确。 由于要在服务器上将结果映射到不同的类上,因此也会增加应用服务器的压力。 当一定会使用到嵌套查询,并且整个复杂的SQL执行速度很快时,建议使用关联的其那套结果查询。


    方式二:使用resultMap配置一对一映射

    UserMapper接口增加接口方法

    // 使用resultMap配置一对一映射
    SysUser selectSysUserAndSysRoleById2(Long id);
    

    UserMapper.xml增加SQL

    <!-- 使用resultMap配置一对一映射 -->
    	<resultMap id="userRoleMap" 
    			   type="com.artisan.mybatis.xml.domain.SysUser">
    		<id column="id" property="id" />
    		<result property="userName" column="user_name" />
    		<result property="userPassword" column="user_password" />
    		<result property="userEmail" column="user_email" />
    		<result property="userInfo" column="user_info" />
    		<result property="headImg" column="head_img" jdbcType="BLOB" />
    		<result property="createTime" column="create_time" jdbcType="TIMESTAMP" />
    		<!-- sysRole相关的属性 -->
    		<result property="sysRole.id" column="role_id"/>
    		<result property="sysRole.roleName" column="role_name"/>
    		<result property="sysRole.enabled" column="enabled"/>
    		<result property="sysRole.createBy" column="create_by"/>
    		<result property="sysRole.createTime" column="role_create_time" jdbcType="TIMESTAMP"/>
    	</resultMap>
    

    这种配置和上一个配置相似的地方在于,sysRole中的property配置部分使用“sysRole.”前缀,在column部分,为了避免不同表中存在相同的的字段,所有可能重名的列都加了 “role_”前缀。

    这种方式配置的时候,还需要再查询时设置不同的列名,别名和resultMap配置的colunm一致。 然后使用resultMap配置映射。

    <!-- 使用resultMap配置一对一映射 -->
    	<select id="selectSysUserAndSysRoleById2" resultMap="userRoleMap">
    		SELECT
    			u.id,
    			u.user_name ,
    			u.user_password ,
    			u.user_email ,
    			u.user_info ,
    			u.create_time ,
    			u.head_img ,
    			r.id role_id,
    			r.role_name ,
    			r.enabled ,
    			r.create_by ,
    			r.create_time role_create_time 
    		FROM
    			sys_user u
    		INNER JOIN sys_user_role ur ON u.id = ur.user_id
    		INNER JOIN sys_role r ON ur.role_id = r.id
    		WHERE
    			u.id = #{id}
    	</select>
    

    单元测试

    @Test
    	public void selectSysUserAndSysRoleById2Test() {
    		logger.info("selectSysUserAndSysRoleById2Test");
    		// 获取SqlSession
    		SqlSession sqlSession = getSqlSession();
    		try {
    			// 获取UserMapper接口
    			UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    			// 注意:数据库中id=1的用户拥有2个角色,不适合这个例子。
    			// 调用selectSysUserAndSysRoleById方法,查询id=1001的用户及其角色
    			SysUser sysUser = userMapper.selectSysUserAndSysRoleById2(1001L);
    			// 期望用户不为空
    			Assert.assertNotNull(sysUser);
    			// 期望角色不为空
    			Assert.assertNotNull(sysUser.getSysRole());
    
    			logger.info(sysUser);
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			sqlSession.close();
    			logger.info("sqlSession close successfully ");
    		}
    	}
    	
    

    日志

    2018-04-30 00:52:25,287  INFO [main] (BaseMapperTest.java:26) - sessionFactory bulit successfully
    2018-04-30 00:52:25,291  INFO [main] (BaseMapperTest.java:29) - reader close successfully
    2018-04-30 00:52:25,295  INFO [main] (UserMapperTest.java:1032) - selectSysUserAndSysRoleById2Test
    2018-04-30 00:52:25,390 DEBUG [main] (BaseJdbcLogger.java:145) - ==>  Preparing: SELECT u.id, u.user_name , u.user_password , u.user_email , u.user_info , u.create_time , u.head_img , r.id role_id, r.role_name , r.enabled , r.create_by , r.create_time role_create_time FROM sys_user u INNER JOIN sys_user_role ur ON u.id = ur.user_id INNER JOIN sys_role r ON ur.role_id = r.id WHERE u.id = ? 
    2018-04-30 00:52:25,519 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: 1001(Long)
    2018-04-30 00:52:25,559 TRACE [main] (BaseJdbcLogger.java:151) - <==    Columns: id, user_name, user_password, user_email, user_info, create_time, head_img, role_id, role_name, enabled, create_by, role_create_time
    2018-04-30 00:52:25,561 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1001, artisan, 123456, test@artisan.com, <<BLOB>>, 2018-04-13 21:12:47.0, <<BLOB>>, 2, 普通用户, 1, 1, 2018-04-13 21:12:46.0
    2018-04-30 00:52:25,572 DEBUG [main] (BaseJdbcLogger.java:145) - <==      Total: 1
    2018-04-30 00:52:25,573  INFO [main] (UserMapperTest.java:1046) - SysUser [id=1001, userName=artisan, userPassword=123456, userEmail=test@artisan.com, userInfo=测试用户, headImg=[18, 49, 35, 18, 48], createTime=Fri Apr 13 21:12:47 BOT 2018, sysRole=SysRole [id=2, roleName=普通用户, enabled=1, createBy=1, createTime=Fri Apr 13 21:12:46 BOT 2018, user=null, privilegeList=null]]
    2018-04-30 00:52:25,580  INFO [main] (UserMapperTest.java:1051) - sqlSession close successfully 
    
    

    这种方法是不是和第一种使用自动映射处理一对一映射相比起来,resultMap相当麻烦?

    事实上 ,resultMap映射是可以被继承的,因此要先简化上面的resultMap的配置。 因为我们这个映射文件中本来就存在一个userMap的映射配置,改造如下

    <!-- 使用resultMap配置一对一映射  继承原有的resultMap -->
    	<resultMap id="userRoleMap_byExtends"  extends="userMap"
    			   type="com.artisan.mybatis.xml.domain.SysUser">
    		<!-- sysRole相关的属性 -->
    		<result property="sysRole.id" column="role_id"/>
    		<result property="sysRole.roleName" column="role_name"/>
    		<result property="sysRole.enabled" column="enabled"/>
    		<result property="sysRole.createBy" column="create_by"/>
    		<result property="sysRole.createTime" column="role_create_time" jdbcType="TIMESTAMP"/>
    	</resultMap>
    	
    

    使用继承不仅可以简化配置,而且当对主表userMap进行修改时也只需要修改一处。 虽然还不是太方便,至少简洁了一点。 要想更加简洁,只有派上asscociation了,请往下看

    测试过了,就不贴代码了,github上已经托管。


    方式三:使用resultMap的asscociation标签配置一对一映射

    在resultMap中,association标签用于和一个复杂的类型进行关联,即用于一对一的关联配置。

    UserMapper接口增加接口方法

    // 使用resultMap配置一对一映射 resultMap association
    SysUser selectSysUserAndSysRoleById4(Long id);
    

    UserMapper.xml增加SQL

    在上面的基础上,再做修改,改成association标签的配置方式。

    	<!-- 使用resultMap配置一对一映射  使用association -->
    	<resultMap id="userRoleMap_byExtendsAndAssociation"  extends="userMap"
    			   type="com.artisan.mybatis.xml.domain.SysUser">
    		<association property="sysRole" columnPrefix="sysRole_"
    			javaType="com.artisan.mybatis.xml.domain.SysRole">
    			<result property="id" column="id"/>
    			<result property="roleName" column="role_name"/>
    			<result property="enabled" column="enabled"/>
    			<result property="createBy" column="create_by"/>
    			<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
    		</association>	   
    	</resultMap>
    	
    
    
    <!-- 使用resultMap配置一对一映射 result中Map中使用association  -->
    	<select id="selectSysUserAndSysRoleById4" resultMap="userRoleMap_byExtendsAndAssociation">
    		SELECT
    			u.id,
    			u.user_name ,
    			u.user_password ,
    			u.user_email ,
    			u.user_info ,
    			u.create_time ,
    			u.head_img ,
    			r.id sysRole_id,
    			r.role_name sysRole_role_name,
    			r.enabled sysRole_enabled,
    			r.create_by sysRole_create_by,
    			r.create_time sysRole_create_time
    		FROM
    			sys_user u
    		INNER JOIN sys_user_role ur ON u.id = ur.user_id
    		INNER JOIN sys_role r ON ur.role_id = r.id
    		WHERE
    			u.id = #{id}
    	</select>
    
    
    

    association标签包含如下主要属性

    • property:对应实体列中的属性名,必填
    • javaType:属性对应的Java类型
    • resultMap:可以直接使用现有的resultMap,从而不需要在这里配置
    • colunmPrefix: 查询列的前缀,配置前缀后,在子标签配置result的colunm时,可以省略前缀
    • 其他属性,略…

    因为配置了列的前缀,因此还需要SQL,如上所示。

    使用association配置还可以使用resultMap属性配置成一个已经存在的resultMap映射。 我们吧sys_role相关的映射提取出来,改造如下

    	<!-- 使用resultMap配置一对一映射  使用association -->
    	<resultMap id="roleMap"  type="com.artisan.mybatis.xml.domain.SysRole" >
    		<id  property="id" column="id"/>
    		<result property="roleName" column="role_name"/>
    		<result property="enabled" column="enabled"/>
    		<result property="createBy" column="create_by"/>
    		<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
    	</resultMap>
    	
    	<resultMap id="userRoleMap_byExtendsAndAssociation_ResultMap"  extends="userMap"
    			   type="com.artisan.mybatis.xml.domain.SysUser">
    		<association property="sysRole" columnPrefix="sysRole_"
    			javaType="com.artisan.mybatis.xml.domain.SysRole" resultMap="roleMap">
    		</association>	   
    	</resultMap>
    

    到这里,是不是没有这么麻烦了? 还有一个需要注意的地方:roleMap我们目前是写在UserMapper.xml中,更合理的应该在RoleMapper.xml中。如果真的在RoleMapper.xml中的话,,通过resultMap来引用的话,就必须要加上命名空间了。 如果不加的话,MyBatis会默认添加调用者当前命名空间的前缀。

    <resultMap id="userRoleMap_byExtendsAndAssociation_ResultMap"  extends="userMap"
    			   type="com.artisan.mybatis.xml.domain.SysUser">
    		<association property="sysRole" columnPrefix="sysRole_"
    			javaType="com.artisan.mybatis.xml.domain.SysRole" resultMap="com.artisan.mybatis.xml.mapper.RoleMapper.roleMap">
    		</association>	   
    	</resultMap>
    

    单元测试

    @Test
    	public void selectSysUserAndSysRoleById4Test() {
    		logger.info("selectSysUserAndSysRoleById4Test");
    		// 获取SqlSession
    		SqlSession sqlSession = getSqlSession();
    		try {
    			// 获取UserMapper接口
    			UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    			// 注意:数据库中id=1的用户拥有2个角色,不适合这个例子。
    			// 调用selectSysUserAndSysRoleById4方法,查询id=1001的用户及其角色
    			SysUser sysUser = userMapper.selectSysUserAndSysRoleById4(1001L);
    			// 期望用户不为空
    			Assert.assertNotNull(sysUser);
    			// 期望角色不为空
    			Assert.assertNotNull(sysUser.getSysRole());
    
    			logger.info(sysUser);
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			sqlSession.close();
    			logger.info("sqlSession close successfully ");
    		}
    	}
    

    日志

    2018-05-01 01:08:18,898  INFO [main] (BaseMapperTest.java:26) - sessionFactory bulit successfully
    2018-05-01 01:08:18,905  INFO [main] (BaseMapperTest.java:29) - reader close successfully
    2018-05-01 01:08:18,913  INFO [main] (UserMapperTest.java:1083) - selectSysUserAndSysRoleById4Test
    2018-05-01 01:08:19,019 DEBUG [main] (BaseJdbcLogger.java:145) - ==>  Preparing: SELECT u.id, u.user_name , u.user_password , u.user_email , u.user_info , u.create_time , u.head_img , r.id sysRole_id, r.role_name sysRole_role_name, r.enabled sysRole_enabled, r.create_by sysRole_create_by, r.create_time sysRole_create_time FROM sys_user u INNER JOIN sys_user_role ur ON u.id = ur.user_id INNER JOIN sys_role r ON ur.role_id = r.id WHERE u.id = ? 
    2018-05-01 01:08:19,155 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: 1001(Long)
    2018-05-01 01:08:19,212 TRACE [main] (BaseJdbcLogger.java:151) - <==    Columns: id, user_name, user_password, user_email, user_info, create_time, head_img, sysRole_id, sysRole_role_name, sysRole_enabled, sysRole_create_by, sysRole_create_time
    2018-05-01 01:08:19,213 TRACE [main] (BaseJdbcLogger.java:151) - <==        Row: 1001, artisan, 123456, test@artisan.com, <<BLOB>>, 2018-04-13 21:12:47.0, <<BLOB>>, 2, 普通用户, 1, 1, 2018-04-13 21:12:46.0
    2018-05-01 01:08:19,231 DEBUG [main] (BaseJdbcLogger.java:145) - <==      Total: 1
    2018-05-01 01:08:19,232  INFO [main] (UserMapperTest.java:1097) - SysUser [id=1001, userName=artisan, userPassword=123456, userEmail=test@artisan.com, userInfo=测试用户, headImg=[18, 49, 35, 18, 48], createTime=Fri Apr 13 21:12:47 BOT 2018, sysRole=SysRole [id=2, roleName=普通用户, enabled=1, createBy=1, createTime=Fri Apr 13 21:12:46 BOT 2018, user=null, privilegeList=null]]
    2018-05-01 01:08:19,239  INFO [main] (UserMapperTest.java:1102) - sqlSession close successfully 
    
    

    方式四:asscociation标签的嵌套查询

    前面三种方式通过负载的SQL查询获取结果,其实还可以利用简单的SQL通过多次查询转换为我们需要的结果,这种方式与根据业务逻辑手动执行多次SQL的方式很像,最后将结果组成一个对象。

    场景和情况比较复杂,后续单独阐述

    展开全文
  • Python中的映射类型详解

    千次阅读 2020-07-18 13:50:11
    非抽象映射类型一般不会直接继承这些抽象基类,它们会直接dict或者是collections.UserDict进行扩展.这些抽象基类的主要作用事作为形式化的文档,它们定义了构建映射类型所需要的最基本的接口.然后它们还可以跟...

    泛映射类型

    collections.abc模块中有Mapping和MutableMapping这两个抽象基类,它们的作用事为dict和其他类似的类型定义形式接口
    非抽象映射类型一般不会直接继承这些抽象基类,它们会直接对dict或者是collections.UserDict进行扩展.这些抽象基类的主要作用事作为形式化的文档,它们定义了构建一个映射类型所需要的最基本的接口.然后它们还可以跟isinstance一起被用来判定某个数据是不是广义上的映射类型:

    from collections.abc import Mapping, MutableMapping

    标准库里的所有映射类型都是利用dict来实现的,因此它们有个共同的限制,即只有<可散列的>数据类型才能用作这些映射里的键.

    什么是可散列的数据类型?

    如果一个对象是可散列的,那么在这个对象的生命周期中,它的散列值是不变的,而且这个对象需要实现__hash__()方法.

    另外可散列对象还要有__eq__()方法,这样才能跟其他键作比较.如果两个可散列对象是相等的,那么它们的散列值一定是一样的.

    原子不可变数据类型(str,bytes和数值类型)都是可散列类型,frozenset也是可散列的,因为根据其定义,frozenset里只能容纳可散列类型.

    元组的话,只有当一个元组包含的所有元素都是可散列类型的情况下,它才是可散列的.

    tt = (1, 2, (30, 40))
    print(hash(tt))  # 8027212646858338501
    tl = (1, 2, [30, 40])
    # print(hash(tl))  # TypeError: unhashable type: 'list'
    tf = (1, 2, frozenset([30, 40]))
    print(hash(tf))  # 985328935373711578
    

    一般来讲,用户自定义的类型的对象都是可散列的,散列值就是它们的id()函数的返回值,所以所有这些对象在比较的时候都是不相等的.

    如果一个对象实现了__eq__方法,并且在方法中用到了这个对象的内部状态的话,那么只有当所有这些内部状态都是不可变的情况下,这个对象踩死可散列的.

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:531509025
    寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
    '''
    class A:
        def __init__(self, a_):
            self.a = a_
    
    
    class B:
        def __init__(self, a_):
            self.a = a_
    
        def __hash__(self):
            return hash(self.a)
    
        def __eq__(self, other):
            return hash(self) == hash(other)
    
    
    a1 = A(1)
    a2 = A([1, 2, 3])
    print(hash(a1))  # -9223371857585079499
    print(hash(a2))  # 179269859620
    
    b1 = B(1)
    b2 = B([1, 2])
    print(hash(b1))  # 1
    # print(hash(b2))  # TypeError: unhashable type: 'list'
    
    # 根据这些定义,字典提供了很多种构造方法.
    a = dict(one=1, two=2, three=3)
    b = {'one': 1, 'two': 2, 'three': 3}
    c = dict(zip(['one', 'two', 'three'], [1, 2, 3]))
    d = dict([('one', 1), ('two', 2), ('three', 3)])
    e = dict({'one': 1, 'two': 2, 'three': 3})
    print(a == b == c == d == e)
    

    字典推导式

    字典推导可以从任何以键值对作为元素的可迭代对象中构建出字典

    STUDENTS = [
        ("孙悟空", 100),
        ("猪八戒", 90),
        ("沙和尚", 80),
        ("二郎神", 70),
        ("哪吒", 60),
        ("诸葛亮", 50),
    ]
    student = {name: number for name, number in STUDENTS}
    print(student)  # {'孙悟空': 100, '猪八戒': 90, '沙和尚': 80, '二郎神': 70, '哪吒': 60, '诸葛亮': 50}
    student2 = {name: number for name, number in student.items() if number > 60}
    print(student2)  # {'孙悟空': 100, '猪八戒': 90, '沙和尚': 80, '二郎神': 70}
    

    常见的映射方法

    dict.update(m, [**kargs])方法处理参数m的方式,是典型的’鸭子类型’,函数首先检查m是否有keys方法,如果有,那么update函数就把它当作映射对象来处理.

    否则,函数会退一步,转而把m当作包含了键值对(key, value)元素的迭代器.python里大多数映射类型的构造方法都采用了类似的逻辑,因此你既可以用一个映射对象来新建一个映射对象,也可以用包含(key, value)元素的可迭代对象来初始化一个映射对象.

    print(student)  # {'孙悟空': 100, '猪八戒': 90, '沙和尚': 80, '二郎神': 70, '哪吒': 60, '诸葛亮': 50}
    student.update({"小白龙": 80, "唐僧": 90})
    print(student)  # {'孙悟空': 100, '猪八戒': 90, '沙和尚': 80, '二郎神': 70, '哪吒': 60, '诸葛亮': 50, '小白龙': 80, '唐僧': 90}
    student.update([("李世民", 90), ("朱元璋", 85)])
    # {'孙悟空': 100, '猪八戒': 90, '沙和尚': 80, '二郎神': 70, '哪吒': 60, '诸葛亮': 50, '小白龙': 80, '唐僧': 90, '李世民': 90, '朱元璋': 85}
    print(student)
    

    用setdefault处理找不到的键

    当字典d[k]不能找到正确的键的时候,Python会抛出异常,这个行为符合Python所信奉的’快速失败’哲学.

    也许每个Python程序员都知道可以用d.get(k, default)来代替d[k],给找不到的键一个默认的返回值.这比处理KeyError要方便不少.

    但是要更新某个键对应的值的时候,不管用__getitem__还是get都会不自然,而且效率低.

    例1

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:531509025
    寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
    '''
    import re
    
    WORD_RE = re.compile(r'\w+')
    index = {}
    with open('./word', encoding='utf-8') as fp:
        for line_no, line in enumerate(fp, 1):
            # re.finditer(string) 返回string中所有与pattern相匹配的全部字串,返回形式为迭代器。
            for match in WORD_RE.finditer(line):
                word = match.group()  # 匹配到的单词
                column_no = match.start() + 1  # 单词首字目所在的位置,从1开始
                location = (line_no, column_no)  # (行号, 列号)
                # 这其实是一种很不好的实现,这样写只是为了证明论点
                occurrences = index.get(word, [])  # 提取word出现的情况,如果还没有它的记录,返回[].
                occurrences.append(location)  # 把单词出现的位置添加到列表的后面.
                index[word] = occurrences  # 把新的列表放回字典中,这又牵扯到一次查询操作.
        # 以字母顺序打印出结果
        # sorted函数的key=参数没有调用str.upper,而是把这个方法的引用传递给sorted函数,这样在排序的时候,单词会被规范成统一格式.
        for word in sorted(index, key=str.upper):  # 将方法用作一等函数
            print(word, index[word])
    
    index_ = {}
    
    with open('./word', encoding='utf-8') as fp:
        for line_no, line in enumerate(fp, 1):
            for match in WORD_RE.finditer(line):
                word = match.group()
                column_no = match.start() + 1
                location = (line_no, column_no)
                index_.setdefault(word, []).append(location)
        for word in sorted(index_, key=str.upper):
            print(word, index_[word])
    

    dict.setdefault(key, []).append(new_value)

    获取单词的出现情况列表,如果单词不存在,把单词和一个空列表放进映射,然后返回这个空列表,这样就能在不进行第二次查找的情况下更新列表了.

    也就是说,和下面的代码效果一样

    if key not in dict:
        dict[key] = []
    dict[key].append(new_value)
    

    只不过,后者至少要进行两次键查询,如果键不存在的话,就是三次.而setdefault只需要一次就可以完成整个操作

    映射的弹性键查询

    有时候为了方便起见,就算某个键在映射里不存在,我们也希望在通过这个键读取值的时候能得到一个默认值.有两个途径能帮我们达到这个目的,一个是通过defaultdict这个类型而不是普通的dict,另一个是给自己定义一个dict的子类,然后再子类中实现__missing__方法.

    在用户创建defalutdict对象的时候,就需要给它配置一个为找不到的键创造默认值的方法.
    具体而言,在实例化一个defaultdict的时候,需要给构造方法提供一个可调用对象,这个可调用对象会在__getitem__碰到找不到的键的时候被调用,让__getitem__返回某种默认值

    比如,我们新建了这样一个字典:dd = defaultdict(list),如果键’new-key’在dd中还不存在的话,表达式dd[‘new-key’]会按照以下的步骤来执行:

    1.调用list()来建立一个新列表
    2.把这个新列表作为值,'new-key’作为它的键,放到dd中
    3.返回这个列表的引用

    而这个用来生成默认值的可调用对象存放在名为default_factory的实例属性中

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:531509025
    寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
    '''
    from collections import defaultdict
    
    # 把list构造方法作为default_factory来创建一个defaultdict
    index_dd = defaultdict(list)
    
    with open('./word', encoding='utf-8') as fp:
        for line_no, line in enumerate(fp, 1):
            for match in WORD_RE.finditer(line):
                word = match.group()
                column_no = match.start() + 1
                location = (line_no, column_no)
                """
                如果index_dd并没有word记录,那么default_factory会被调用,为查询步到的键创造一个值.
                这个值在这里是一个空列表,然后这个空列表会被赋值给index_dd[word],继而被当作返回值返回.
                因此.append(location)操作总能成功
                """
                index_dd[word].append(location)
        for word in sorted(index_, key=str.upper):
            print(word, index_dd[word])
    

    如果在创建defaultdict的时候没有指定default_factory,查询不存在的键会触发KeyError
    defaultdict里的default_factory只会在__getitem__里被调用,在其他的方法里完全不会发挥作用.
    比如dd[k]这个表达式会调用default_factory创造某个默认值,而dd.get(k)则会返回None

    所有这一切背后的功臣其实是特殊方法__missing__.它会在defaultdict遇到找不到的键的时候调用default_factory,而实际上这个特性是所有映射类型都可以选择去支持的.

    所有的映射类型在处理找不到的键的时候,都会牵扯到__missing__方法.这也是这个方法被称作’'missing的原因.

    虽然基类dict没有定义这个方法,但是dict是知道有这个东西存在的.也就是说,如果有一个类继承了dict,然后这个继承类提供了__missing__方法,那么在__getitem__碰到找不到的键的时候,Python就会自动调用它,而不是抛出KeyError异常.

    __missing__方法只会被__getitem__调用,对get或者__contains__这些方法的使用没有影响.

    class StrKeyDict(dict):  # 继承dict
        """
        如果要自定义一个映射类型,更合适的策略其实是继承collections.UserDict类.这里我们从dict继承,
        只是为了演示__missing__是如何被dict.__getitem__调用的
        """
    
        def __missing__(self, key):
            """
            为什么isinstance(key, str)是必须的?
            如果没有这个测试,当str(key)不是一个存在的键,代码就会陷入无限递归.这是因为__missing__的最后一行中的self[str(key)]会调用
            __getitem__,而这个str(key)又不存在,于是__missing__又会被调用.
            """
            if isinstance(key, str):  # 如果找不到的键本身就是字符串,那就抛出KeyError异常
                raise KeyError(key)
            # 如果找不到的键不是字符串,那么就把它转换成字符串再进行查找
            return self[str(key)]
    
        def get(self, key, default=None):
            """
            get方法把查找工作用self[key]的形式委托给__getitem__,这样在宣布查找失败之前,还能通过__missing__再给某个键一个机会
            """
            try:
                return self[key]
            except KeyError:
                # 如果抛出KeyError,那么说明__missing__也失败了,于是返回default.
                return default
    
        def __contains__(self, item):
            """
            为了保持一致性,__contains__方法也是必须的.这是因为k in d这个操作会调用它,但是我们从dict继承到的__contains__方法[不会]在找不到键的时候
            调用__missing__方法.__contains__里还有个细节,就是我们这里没有用更具Python风格的方式--item in self--来检验是否存在,因为那也会导致
            __contains__被递归调用,为了避免这一情况,这里采取了更显式的方法,直接在这个self.keys()里查询.
    
            像k in my_dict.keys()这种操作在Python3中是很快的,而且即便映射类型对象很庞大也没关系.这因为dict.keys()的返回值是一个"视图".
            视图就像一个集合,而且跟字典类似的是,在视图里查找一个元素的速度很快.
            Python2中的dict.keys()返回的则是一个列表,它在处理体积大的对象的时候效率不会太高,因为k in my_list操作需要扫描整个列表.
            """
            # 先安装传入键的原本的值来查找,如果没找到,再用str()方法把键转换成字符串再查找一次.
            return item in self.keys() or str(item) in self.keys()
    
    
    d = StrKeyDict([('2', 'two'), ('4', 'four')])
    print(d['2'])  # two
    print(d[4])  # four
    # print(d[1])  # KeyError: '1'
    
    print(d.get('2'))  # two
    print(d.get(4))  # four
    print(d.get(1))  # None
    
    print(2 in d)  # True
    print(1 in d)  # False
    

    字典的变种

    from collections import OrderedDict, ChainMap, Counter, UserDict
    

    collections.OrderedDict

    这个类型在添加键的时候会保持顺序,因此键的迭代次序总是一致的.OrderedDict的popitem方法默认删除并返回的是字典里的最后一个元素.

    但是如果像my_dict.popitem(last=False)这样调用它,那么它删除并返回第一个被添加进去的元素.

    collections.ChainMap

    该类型可以容纳数个不同的映射对象,然后在进行键查找操作的时候,这些对象会被当作一个整体被逐个查找,直到键被找到为止.

    这个功能在给有嵌套作用域的语言做解释器的时候很有用,可以用一个映射对象来代表一个作用域的上下文.

    例如下面这个Python变量查询规则:

    import builtins
    
    py_lookup = ChainMap(locals(), globals(), vars(builtins))
    
    """
    collections.Counter
    这个映射类型会给键准备一个整数计数器.每次更新一个键的时候都会增加这个计数器.所以这个类型可以用来给可散列列表对象计数,
    或者是当成多重集来用--多重集合就是集合里的元素可以出现不止一次.Counter实现了+和-运算符用来合并记录,还有像most_common([n])这类很有用的方法.
    most_common([n])会按照次序返回映射里最常见的n个键和它们的计数.
    下面的小例子利用Counter来计算单词中各个字母出现的次数:
    """
    ct = Counter('abracadabra')
    print(ct)  # Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
    ct.update('aaaaazzz')
    print(ct)  # Counter({'a': 10, 'z': 3, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
    print(ct.most_common(2))  # [('a', 10), ('z', 3)]
    

    collections.UserDict

    这个类其实就是把标准的dict用纯Python又实现了一遍.跟前三者不同,UserDict是让用户继承写子类的.下面就来试试:

    就创造自定义映射类型来说,以UserDict为基类,总比以普通的dict为基类要来得方便.这体现在,我们能够改进上面的StrKeyDict类,使得所有的键都存储为字符串类型.

    而更倾向于从UserDict而不是从dict继承的主要原因是,后者有时会在某些方法的实现上走一些捷径,导致我们不得不在它的子类中重写这些方法,但是UserDict就不会带来这些问题.

    另外一个需要注意的地方是UserDict并不是dict的子类,但是UserDict有一个叫做data的属性,是dict的实例,这个属性实际上是UserDict最终存储数据的地方.

    这样做的好处是,比起上面的例子,UserDict的子类就能在实现__setitem__的时候避免不必要的递归,也可以让__contains__里的代码更简洁.

    下面的雷子不但把所有的键都以字符串的形式存储,还能处理一些创建或者更新实例时包含非字符串类型的键这类意外情况.

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:531509025
    寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
    '''
    class StrKeyDict_U(UserDict):  # StrKeyDict_U是对UserDict的拓展
        def __missing__(self, key):
            if isinstance(key, str):
                raise KeyError(key)
            return self[str(key)]
    
        def __setitem__(self, key, value):
            # 把所有的键都转换成字符串.由于把具体的实现委托给了self.data属性,这个方法写起来也不难.
            self.data[str(key)] = value
    
        def __contains__(self, item):
            # 这里可以放心假设所有已经存储的键都是字符串.
            # 并且可以直接在self.data上查询
            return str(item) in self.data
    

    因为UserDict继承的是MutableMapping,所以StrKeyDict_U里剩下的那些映射类型的方法都是从UserDict、MutableMapping和Mapping这些超类继承来的.

    特别是最后的Mapping类,它虽然是一个抽象基类(ABC),但它却提供了好几个实用的方法.

    MutableMapping.update

    这个方法不但可以为我们所直接利用,它还用在__init__里,然构造方法可以利用出入的各种参数(其他映射类型、元素是(key, value)对的可迭代对象和键值参数)来新建实例.因为这个方法在背后是用self[key] = value来添加新值的,所以它其实是在使用我们的__setitem__方法

    Mapping.get

    在StrKeyDict中,我们不得不改写get方法,好让它的表现跟__getitem__一致.而在StrKeyDict_U中就没有这个必要了,因为它继承了Mapping.get方法,这个方法的实现方式跟StrKeyDict.get是一模一样的.

    不可变映射类型

    标准库里的所有映射类型都是可变的,但是有时候我们需要限制用户的修改从Python3.3开始,types模块中引入了一个封装类名叫MappingProxyType.如果给这个类一个映射,它会返回一个只读的映射视图.

    虽然是个只读视图,但是它是动态的.这意味着如果对原映射做出了改动,我们通过这个视图可以观察到,但是无法通过这个视图对原映射做修改.

    from types import MappingProxyType
    d = {1: 'A'}
    d_proxy = MappingProxyType(d)
    print(d_proxy)  # {1: 'A'}
    print(d_proxy[1])  # A   d中的内容可以通过d_proxy看到
    # 但是通过d_proxy并不能做任何修改
    # d_proxy[2] = 'X'  # TypeError: 'mappingproxy' object does not support item assignment
    d[2] = 8
    # d_proxy是动态的,也就是说对d所做的任何改动都会反馈到它的上面
    print(d_proxy[2])  # 8
    
    展开全文
  • 关于python中的映射类型

    千次阅读 2019-09-07 20:04:08
    下面介绍一下python的数据类型相关的题目 ...解析:映射是一种关联式的容器类型,它存储了对象与对象之间映射关系,字典是python里唯一的映射类型,它存储了键值的关联,是由键到键值的映射关系。 ...

    下面介绍一下python的数据类型相关的题目
    1.下列哪种类型是python的映射类型?
    选项:str list tuple dict
    答案:dict
    解析:映射是一种关联式的容器类型,它存储了对象与对象之间映射关系,字典是python里唯一的映射类型,它存储了键值对的关联,是由键到键值的映射关系。

    展开全文
  • Mapping,映射,相当于关系型数据库创建语句,定义文档字段及其类型、索引与存储方式。通常会涉及如下方面: 文档中哪些字段需要定义成全文索引字段。...1.1 映射类型 Elasticsearch支持meta-fields...

    Mapping,映射,相当于关系型数据库创建语句,定义文档字段及其类型、索引与存储方式。通常会涉及如下方面:

    • 文档中哪些字段需要定义成全文索引字段。
    • 文档中哪些字段定义为精确值,例如日期,数字、地理位置等。
    • 文档中哪些字段需要被索引(能通过该字段的值查询文档)。
    • 日期值的格式。
    • 动态添加字段的规则定义等。

    1、类型映射概述
    1.1 映射类型
    Elasticsearch支持meta-fields、fields or properties两种映射类型,将决定文档的索引方式。

    • Meta-fields
      元数据字段用于定义文档的元数据字段的特征,文档的元数据字段主要包括_index、_type、_id、_source这4个字段。

    • Fields or properties
      属性字段列表,通过properties字段定义整个文档有效载荷的各字段的数据类型、分词器等属性。
      映射类型,可以理解为以何种方式来定义索引中一个类型的字段集。

    1.2 数据类型
    每一个字段都会指定一个数据类型,数据类型通常如下:
    简单类型,例如text、keyword、date、long、double、boolean、ip
    复合类型,诸如object(json)、netsed.
    特殊类型,诸如geo_point、geo_shape(地图相关类型)、completion。
    后续章节会单独重点剖析elasticsearch所支持的数据类型。

    1.3 映射保护机制
    es提供如下参数来限制es的行为:

    • index.mapping.total_fields.limit t
      索引中允许定义的最大字段(属性)个数,默认为1000。
    • index.mapping.depth.limit
      字段级联的最大深度,默认为20。
    • index.mapping.nested_fields.limit
      一个索引最多包含字段类型为nested的个数,默认为50。

    1.4 动态映射机制
    与关系型数据库不同的是,一个type(对应关系型数据库的表)中的字段可以在使用过程中动态添加。具体的动态映射机制,将在后续文章中单独结束。

    1.5 更新已有映射定义
    es不支持直接修改已索引的已存在的字段映射,因为修改字段映射,意味着已索引的数据生效,可以使用别名机制来修改字段的名称,如果需要修改已存在字段的映射,建议重新创建一个索引,再使用reindex API迁移数据。

    1.6 索引、type组织方式
    索引在创建时,Elasticsearch6.x版本只支持一个映射类型,而7.x版本后将完成删除映射类型。es5.x中一个索引包含多个type的情况再6.x版本将继续支持查询,7.0版本后,API将完成移除与多类型相关的API。

    Elasticsearch6.x版本后为什么不继续对单一索引库提供多类型支持呢?
    当初,为了方便理解es,通常与关系型数据库进行类比,例如es中的index(索引)相当于关系型数据库的database,而类型(type)相当于关系型数据库中的table。其实这是一个错误的比喻。在关系型数据库中,表是相互独立的,一个表中的列名与另外一个表中的列名相同是没有关系的,但对于es的类型映射定义,情况并非如此。

    在es单一索引中,不同映射类型(type)具有相同名称的字段在内部都是由同一个Lucence字段来存储,这也就意味着同一个索引内不同的类型,如果出现名字相同的字段,其数据类型也必须相同。更重要的是,存储在同一索引中具有很少或没有共同字段的不同类型(实体)会导致数据稀疏,大大降低Lucece高效压缩文档的能力,影响其检索性能。

    基于上述各种原因,故es将在后续版本中不支持一个索引中定义多个类型。

    2、meta-field(元字段)
    每个文档都有与之关联的元数据,例如_index、mapping _type和_id元字段。在创建映射类型时,可以定制其中一些元字段的行为。

    • identity meta-fields(表明文档身份的元字段)
    1. _index
      文档所在的索引,类似于关系型数据库的database。
    2. _uid
      _type与_id的组合,文档的唯一标识。
    3. _type
      文档映射类型。
    4. _id
      文档的_id值。
    • document source meta-fields
    1. _source
      文档的原始json数据。
    2. _size
      文档_souce字段的字节长度,需要插件:mapper-size plugin。
    • indexing meta-fields
    1. _all
      将所有字段映射成一个_all字段,在6.0.0版本后废弃,可以使用copy_to来定义需要聚合的字段。
      _field_names
      _field_names字段,用于索引文档中包含除null之外的任何值的每个字段的名称。exist查询使用这个字段来查找对于特定字段具有或不具有任何非空值的文档,也就是该字段记录的是字段值不为null的所有字段名称。当前版本,_field_names字段不包含启用了doc_values、norm的字段,对于启用doc_values或norm的字段,exist查询仍然可用,但不会使用_field_names字段。
      注:禁用_field_names通常是不必要的,因为它不再承载以前的索引开销。如果你有很多禁用doc_value和norm的字段,并且你不需要使用这些字段执行exist查询,你可能想禁用_field_names,你可以通过如下方式禁用_field_names字段:
    PUT tweets
    {
      "mappings": {
        "_doc": {
          "_field_names": {
            "enabled": false
          }
        }
      }
    }
    
    1. _ignored
      设置为ignore_malformed=true的所有字段。
    • routing meta-field
    1. _routing
      分片路由字段。
    • other meta-field
      1._meta
      用于用户自定义的元数据,例如:
    PUT my_index
    {
      "mappings": {
        "_doc": {
          "_meta": { 
            "class": "MyApp::User",
            "version": {
              "min": "1.0",
              "max": "1.3"
            }
          }
        }
      }
    }
    

    本文初步介绍了Elasticsearch 类型映射与元字段类型,后续文章将介绍映射参数、elasticsearch支持的数据类型、自动类型映射机制等。


    见文如面,我是威哥,热衷于成体系剖析JAVA主流中间件,关注公众号『中间件兴趣圈』,回复专栏可获取成体系专栏导航,回复资料可以获取笔者的学习思维导图。
    在这里插入图片描述

    展开全文
  • 映射类型:字典

    千次阅读 2018-01-02 14:58:42
    字典是一种通过名字引用值的数据结构,字典中的值并没有特殊的顺序,但是都是存储在一个特定的键(Key)里,键可以是数字、字符串或者元组。 1.如何创建字典和给字典赋值 创建字典只需要把字典赋值给一个变量,...
  • Hibernate之两种一对一关系映射方式

    千次阅读 2018-01-15 21:39:22
    前言在前面的Hibernate学习中已经介绍了多一、一多、多多...一种是基于外键的映射关系。一种是基于主键的映射关系。本文将分别从具体案例出发,介绍两种不同的一映射配置。案例说明:需求 一个用户对应一个
  • MyBatis面试题(2020最新版)

    万次阅读 多人点赞 2019-09-24 16:40:33
    整理好的MyBatis面试题库,史上最全的MyBatis面试题,MyBatis面试宝典,特此分享给大家 MyBatis 介绍 MyBatis 是款优秀的...MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plai...
  • 基本映射对一个实体进行映射,关联映射就是处理多个实体之间的关系,将关联关系映射到数据库中,所谓的关联关系在对象模型中有个或多个引用。
  • 1、修改类型映射关系 在项目中,为了降低数据的存储空间,status状态字段一般使用tinyint, 1个tinyint型数据只占用个字节,个int型数据占用四个字节。这看起来似乎差别不大,但是在比较大的表中,字节数的...
  • 文章目录定义示例使用总结 ...#给example索引新增个birthday字段,类型为date, 格式可以是yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss #添加日期类型映射 PUT test_label_supplier/docs/_mapping { "properties":...
  • Mybatis之高级映射一对映射

    千次阅读 2018-09-12 18:07:37
    一对映射(两方式) 三张表关联查询。当然resultType也能实现,需要将所查询的信息定义到个pojo(详情见一对一映射中的resultType),这里讲的是resultMap。 需求:查询人员、部门信息并关联查询其父级部门信息。...
  • Python3入门之——映射类型

    千次阅读 2020-08-31 23:20:02
    映射是键值数据项的组合
  • Hibernate映射类型 Java类型 标准SQL类型 字节大小 integer/int java.lang.Integer/int INTEGER 4Byte long java.lang.Long/long BIGINT 8Byte short java.lang.Short/short SMALLINT...
  • TypeScript实战-18-TS高级类型-映射类型

    千次阅读 2019-09-20 18:56:14
    本篇介绍TS的另个高级类型-映射类型 二,映射类型 映射类型: TS允许将个类型映射成另外个类型 将个接口的所有属性映射为只读: // 定义接口Obj interface Obj { a: number b: string c: boolean } // ...
  • TypeScript的映射类型

    千次阅读 2017-10-27 14:39:00
    映射类型 个常见的任务是将个已知的类型每个属性都变为可选的: interface PersonPartial { name?: string; age?: number; } 或者我们想要个只读版本: interface PersonReadonly { readonly name: ...
  • 从本小节开始我们开始学习es中常用的元数据类型和字段映射,学习和理解它们可以有助于理解es及其工作机制。 其主要分为两大类。 其,元字段,元字段用于ES每个文档自带的元数据结构,包括 _index,_type, _id...
  • 华中科技大学计算机组成原理慕课答案

    万次阅读 多人点赞 2020-01-26 00:09:18
    、单项选择题 1、下列说法中,错误的是( B ) A.固件功能类似软件,形态类似硬件 B.寄存器的数据位微程序级用户透明 C.软件与硬件具有逻辑功能的等效性 D.计算机系统层次结构中,微程序属于硬件级 2、...
  • Mybatis中的关系映射(一对一,一对多,多多) ...
  • mybatis 一对一映射(两方式)

    万次阅读 2015-08-05 20:25:22
    对于一对一的关系映射一共有两解决方案: 开发步骤:1)写OrdersMapperUser.xml文件 2)编写与xml同名的接口OrdersMapperUser 3)测试 声明:一下xml文件的代码都在中 方式:使用包装类完成映射关系(比较容易...
  • 映射类型是一类可迭代的键-值数据项的组合...在python3.1后,还引入了一种有序的映射类型:collections.OrderedDict. 特点: 1.只有可哈希运算的对象可用于映射类型中的键,因此,内置的固定的数据类型都可以用作...
  • java和mysql 的数据类型对照(映射)表 数据类型: java mysql byte tinyint short smallint int int(★) long bigint char / String varchar(★) / char boolean tinyint / int 代替 float / ...
  • Mybatis中一映射详解

    万次阅读 2016-10-23 16:13:25
    这意味着讲师和课程之间存在一对多的映射关系。 注意:在一对多关系中,数据库建表的时候外键一定是在多的那一方建立. 建表语句: drop table courses;表数据中,zs 讲师教授个课程,而 ls 讲师教授两个课程 配置完...
  • Mybatis之输入输出映射(共三种类型)

    千次阅读 2018-12-31 17:38:12
    、输入parameterType输出resultType类型(resultType:列名和pojo中的属性名要一致) Mybatis使用ognl表达式解析对象字段的值,#{}或者${}括号中的值为pojo属性名称,其中,#{}:占位符号,相对于?,${}:sql拼接...
  • 在实际开发中我们不可能只是单表进行操作,必然要操作多表,本文就来讲解多表操作中的一对一关联映射一对多(或多对一)关联映射,至于多多关联映射实质上也是两个一对多(或多对一)关联映射,所以在这里我并不...
  • 下面我来学习es中另外一种重要的字符串类型keyword。 一、概述 关键字。关键字是个精准值,通常用于过滤、排序、参与聚合等。关键字不参与分词。 二、使用 上边介绍的text文本字段在映射时要设置分词器,keyword字段...
  • Spring Data JPA 之 一对一一对多,多多 关系映射

    万次阅读 多人点赞 2018-06-10 17:01:10
    &amp;amp;amp;amp;amp;amp;nbsp; 一、@OneToOne关系映射 JPA使用@OneToOne来标注一一的关系。... People 和 Address 是一一的关系。... 这里用两种方式描述JPA的一一关系。... 一种是通过外键的方式... 另外一种...
  • 在关系型数据库中,表与表之间存在着一对一一对多,多多这几种映射关系。映射关系是mybatis的核心知识,在以后的工作中,我们会经常遇到以上几种映射关系,因此,我们很有必要学好映射关系。 、mybatis 一对...
  • ES学习之单个索引映射多个类型

    万次阅读 2018-06-19 13:31:00
    在ES6.0.0及更高的版本中,创建的索引只能包含映射类型。在6.0.0以下的版本中创建的个索引映射多个类型的索引在6.0.0版本中继续发挥作用,但是将在7.0.0中完全删除。 自第次发布弹出式搜索以来,每个文档都...
  • JPA

    千次阅读 多人点赞 2019-01-05 09:43:11
    今天做东西的时候使用到了JPA,在这里把JPA需要注意的知道的体系结构,给大家罗列遍。如果能帮到大家一点,希望大家,点个赞关注一下,后期还会更新更多技术。 、JPA概述  1.使用JPA持久化对象的步骤 创建 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 686,799
精华内容 274,719
关键字:

列表是一种映射类型对吗