struct sdshdr{
//所保存字符串的长度
int len;
//buf数组中未使用的长度
int free;
//字节数组,保存字符串
char buf[];
}
typedef struct list{
listNode *head;
listNode *tail;
//链表长度
unsigned long len;
//节点复制函数
void *(*dup)(void *ptr);
//节点值释放函数
void *(*free)(void *ptr);
//节点值比对函数
void (*match)(void *ptr,void *key);
}

typedef struct dictht{
// 哈希表数组
dictEntry **table;
// 哈希表大小
long size;
// hash大小掩码,计算索引值 等于size-1
long sizemask;
// 已有节点数量
long used;
}
ht[0]将最后变成空表。HashMap的hash值计算(1) 由很多层结构组成
(2) 每一层都是一个有序的链表
(3) 最底层(Level 1)的链表包含所有元素
(4) 如果一个元素出现在 Level i 的链表中,则它在 Level i 之下的链表也都会出现。
(5) 每个节点包含两个指针,一个指向同一链表中的下一个元素,一个指向下面一层的元素。 ### 总结 - 应用:zset,集群节点中的内部数据结构 ## 集合(整数集合)
列表键时,指的是这个键所对应的值为列表对象。

传统的传递Statement Id 和查询参数给 SqlSession 对象,使用 SqlSession对象完成和数据库的交互;
MyBatis提供了非常方便和简单的API,供用户实现对数据库的增删改查数据操作,以及对数据库连接信息和MyBatis 自身配置信息的维护操作。 
MyBatis 将配置文件中的每一个<mapper> 节点抽象为一个 Mapper 接口,而这个接口中声明的方法和跟<mapper> 节点中的<select|update|delete|insert> 节点项对应;
即<select|update|delete|insert> 节点的id值为Mapper 接口中的方法名称,parameterType 值表示Mapper 对应方法的入参类型,
而resultMap 值则对应了Mapper 接口表示的返回值类型或者返回结果集的元素类型。

根据MyBatis 的配置规范配置好后,通过SqlSession.getMapper(XXXMapper.class) 方法,MyBatis 会根据相应的接口声明的方法信息,通过动态代理机制生成一个Mapper 实例; 我们使用Mapper 接口的某一个方法时,MyBatis 会根据这个方法的方法名和参数类型,确定Statement Id,底层还是通过SqlSession.select(“statementId”,parameterObject); 或者SqlSession.update(“statementId”,parameterObject); 等等来实现对数据库的操作
MyBatis 引用Mapper 接口这种调用方式,纯粹是为了满足面向接口编程的需要。 (其实还有一个原因是在于,面向接口的编程,使得用户在接口上可以使用注解来配置SQL语句,这样就可以脱离XML配置文件,实现“0配置”)。
数据处理层是Mybatis的核心
· 通过传入参数构建动态SQL;
· SQL语句的执行以及封装查询结果集成List
动态 · MyBatis 通过传入的参数值,使用 Ognl 来动态地构造SQL语句,使得MyBatis 有很强的灵活性和扩展性。 · 参数映射指的是对于java 数据类型和jdbc数据类型之间的转换:这里有包括两个过程:查询阶段,我们要将java类型的数据,转换成jdbc类型的数据,通过 preparedStatement.setXXX() 来设值;另一个就是对resultset查询结果集的jdbcType 数据转换成java 数据类型。
SQL语句的执行以及封装查询结果集成List
· SqlSession 作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能
· Executor MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护
· StatementHandler 封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合。
· ParameterHandler 负责对用户传递的参数转换成JDBC Statement 所需要的参数,
· ResultSetHandler 负责将JDBC返回的ResultSet结果集对象转换成List类型的集合;
· TypeHandler 负责java数据类型和jdbc数据类型之间的映射和转换
· MappedStatement MappedStatement维护了一条<select|update|delete|insert>节点的封装,
· SqlSource 负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回
· BoundSql 表示动态生成的SQL语句以及相应的参数信息
· Configuration MyBatis所有的配置信息都维持在Configuration对象之中。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.sukbear.www</groupId>
<artifactId>java-se</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.3</version>
</dependency>
</dependencies>
<build>
<!-- 定义classpath -->
<resources>
<!-- resources文件 -->
<resource>
<directory>src/main/resources</directory>
<!-- 是否被过滤,如果被过滤则无法使用 -->
<filtering>false</filtering>
</resource>
<!-- java文件夹 -->
<resource>
<directory>src/main/java</directory>
<!-- 引入映射文件等 -->
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
</build>
</project>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="logImpl" value="LOG4J"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
<typeAliases>
<!--<package name="tk.mybatis.simple.model"></package>-->
<package name="test.model"></package>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="" value=""/>
</transactionManager>
<dataSource type="UNPOOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="mysql"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 引入Mapper.xml -->
<!-- 用package的前提是对包下的接口,循环按接口限定名tk.mybatis.simple.mapper.UserMapper
转换成tk/mybatis/simple/mapper/UserMapper.xml 然后以.xml后缀搜索XML资源 ,找到就解析。-->
<!-- <mapper resource="tk/mybatis/simple/mapper/UserMapper.xml"/>
<mapper resource="tk/mybatis/simple/mapper/DynamicMapperTest.xml"/>-->
<!-- <mapper resource="test/xml/SysUserMapper.xml"/>-->
<package name="tk.mybatis.simple.mapper"/>
</mappers>
</configuration>
package tk.mybatis.simple.model;
import java.util.Date;
import java.util.List;
/**
* user
*
* @author sukbear
* @create 2018-12-10 16:21
*/
public class SysUser {
private Long id;
private String userName;
private String userPassword;
private String userEmail;
private String userInfo;
private byte[] headImg;
private Date createTime;
private SysRole role;
private List<SysRole> roleList;
public Long getId() {
return id;
}
public List<SysRole> getRoleList() {
return roleList;
}
public void setRoleList(List<SysRole> roleList) {
this.roleList = roleList;
}
public SysRole getRole() {
return role;
}
public void setRole(SysRole role) {
this.role = role;
}
public void setId(Long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
public String getUserEmail() {
return userEmail;
}
public void setUserEmail(String userEmail) {
this.userEmail = userEmail;
}
public String getUserInfo() {
return userInfo;
}
public void setUserInfo(String userInfo) {
this.userInfo = userInfo;
}
public byte[] getHeadImg() {
return headImg;
}
public void setHeadImg(byte[] headImg) {
this.headImg = headImg;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
/* @Override
public String toString() {
return this.id+" "+this.userName;
}*/
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="tk.mybatis.simple.mapper.UserMapper">
<!--建立对象和属性的对应关系-->
<resultMap id="userMap" type="tk.mybatis.simple.model.SysUser">
<id property="id" column="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"/>
</resultMap>
<resultMap id="roleMap" type="tk.mybatis.simple.model.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>
<!-- 返回类型为对象 -->
<!--考虑到性能,最好指定查询列,很少使用*号代替所有列 -->
<select id="findUserByID" parameterType="int" resultType="tk.mybatis.simple.model.SysUser">
SELECT *
FROM sys_user
WHERE id = #{id}
</select>
<!-- 返回类型为之前定义的userMap -->
<!--考虑到性能,最好指定查询列,很少使用*号代替所有列 -->
<select id="selectById" resultMap="userMap">
SELECT *
FROM sys_user
WHERE id = #{id}
</select>
<!-- #{对象的属性名} 用#号(不用$)可以预编译,避免sql注入 -->
<insert id="insert">
INSERT INTO sys_user (
id, user_name, user_password, user_email, user_info, head_img, create_time
) VALUES (
#{id}, #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType=BLOB},
#{createTime, jdbcType=TIMESTAMP}
)
</insert>
<!--利用JDBC返回主键自增的值 {useGeneratedKeys="true"} -->
<insert id="insert2" useGeneratedKeys="true" keyProperty="id">
INSERT INTO sys_user (
id, user_name, user_password, user_email, user_info, head_img, create_time
) VALUES (
#{id}, #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType=BLOB},
#{createTime, jdbcType=TIMESTAMP}
)
</insert>
<!-- 使用selectKey返回主键的值 不同数据库selectKey不同 -->
<insert id="insert3">
INSERT INTO sys_user (
id, user_name, user_password, user_email, user_info, head_img, create_time
) VALUES (
#{id}, #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType=BLOB},
#{createTime, jdbcType=TIMESTAMP}
)
<selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER">
SELECT last_insert_id()
</selectKey>
</insert>
<select id="selectAll" resultMap="userMap">
SELECT *
FROM sys_user
</select>
<!-- -->
<select id="selectRolesByUserId" resultMap="roleMap">
SELECT
r.id,
r.role_name roleName,
r.enabled enabled,
r.create_by createBy,
r.create_time createTime,
u.user_name AS "user.userName",
u.user_email AS "user.userEamil"
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 = #{userId}
</select>
<!-- 根据id更新user的信息 -->
<update id="updateById">
UPDATE sys_user
SET
user_name = #{userName},
user_password = #{userPassword},
user_email = #{userEmail},
user_info = #{userInfo},
head_img = #{headImg,jdbcType=BLOB},
create_time = #{createTime,jdbcType=TIMESTAMP}
WHERE id = #{id}
</update>
<!-- 根据主键删除列 -->
<delete id="deleteById">
DELETE FROM sys_user
WHERE id = #{id}
</delete>
<!-- 多个接口参数(param("userId"))-->
<!-- 给参数配置@param注解后 mybatis自动将参数封装成Map @param的值成为key 故在SQL部分可以用配置的注解值来使用参数-->
<!--当参数时javaBean时要通过 对象.属性 比如 (@param("obj") Object obj) 在sql使用的时候就是obj.properties -->
<select id="selectRolesByUserIdAndRoleEnabled" resultType="tk.mybatis.simple.model.SysRole">
SELECT
r.id,
r.role_name roleName,
r.enabled enabled,
r.create_by createBy,
r.create_time createTime
FROM sys_user u
INNER JOIN sys_user_role ur ON ur.user_id = u.id
INNER JOIN sys_role r ON ur.role_id = r.id
WHERE u.id = #{userId} AND r.enabled = #{enabled}
</select>
<select id="selectRolesByUserIdAndRoleEnabledUseJavaBean" resultType="tk.mybatis.simple.model.SysRole">
SELECT
r.id,
r.role_name roleName,
r.enabled enabled,
r.create_by createBy,
r.create_time createTime
FROM sys_user u
INNER JOIN sys_user_role ur ON ur.user_id = u.id
INNER JOIN sys_role r ON ur.role_id = r.id
WHERE u.id = #{user.id} AND r.enabled = #{role.enabled}
</select>
</mapper>
package tk.mybatis.simple.mapper;
import org.apache.ibatis.annotations.Param;
import tk.mybatis.simple.model.SysRole;
import tk.mybatis.simple.model.SysUser;
import java.util.List;
/**
* usermapper
*
* @author sukbear
* @create 2018-12-10 16:31
*/
public interface UserMapper {
SysUser selectById(Long id);
int insert(SysUser sysUser);
int insert2(SysUser sysUser);
int insert3(SysUser sysUser);
List<SysUser> selectAll();
List<SysRole> selectRolesByUserId(Long userId);
int updateById(SysUser sysUser);
int deleteById(Long id);
List<SysRole> selectRolesByUserIdAndRoleEnabled(@Param("userId") Long userId, @Param("enabled") Integer enabled);
List<SysRole> selectRolesByUserIdAndRoleEnabledUseJavaBean(@Param("user") SysUser user, @Param("role") SysRole role);
}
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
// 取得当前线程的 LocaleContext 。默认为空
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
// 创建LocaleContext,该接口表示区域内容。主要作用是封装请求的 Locale 信息
LocaleContext localeContext = buildLocaleContext(request);
// 取得当前线程的 RequestAttributes 。默认为空
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
// 2.创建 RequestAttributes,该接口封装了本次请求的 rqeust,response 信息。通过它可以很方便的操作 rqeust 的属性
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
// 3.初始化 ContextHolders
initContextHolders(request, localeContext, requestAttributes);
try {
// 服务处理,留给子类实现
doService(request, response);
}
catch (ServletException ex) {
failureCause = ex;
throw ex;
}
catch (IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
// 5. 释放 ContextHolders
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
if (logger.isDebugEnabled()) {
if (failureCause != null) {
this.logger.debug("Could not complete request", failureCause);
}
else {
if (asyncManager.isConcurrentHandlingStarted()) {
logger.debug("Leaving response open for concurrent processing");
}
else {
this.logger.debug("Successfully completed request");
}
}
}
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
protected abstract void doService(HttpServletRequest request, HttpServletResponse response)throws Exception;
可以看出,FrameworkServlet把GET请求和POST请求都统一用processRequest()来处理,而具体的服务细节交给子类DispatcherServlet去处理。
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
}
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<String, Object>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// Make framework objects available to handlers and view objects.
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
try {
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
doDispatch()方法源码:该过程是负责请求的真正处理
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 1. 判断用户的请求是否为文件上传,通过MultipartResolver解析
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 2. 通过HandlerMapping映射处理器和拦截器包装成一个HandlerExecutionChain
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// 3. 将处理器包装成相应的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 省略此处代码
// 4. 执行处理器相关的拦截器的预处理
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 5. 由适配器执行处理器
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(request, mv);
// 6. 拦截器后处理
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
// 7. 视图渲染
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
// 此处省略部分代码
}
我们每次使用命令
git clone git@gitlab.xxx.com:xxxxx.git
默认 clone 的是这个仓库的 master 分支。如果最新的代码不在 master 分支上,该如何拿到呢?
直接使用命令
git branch -r #查看远程分支
或
git branch -a #查看所有分支
会显示
origin/HEAD -> origin/master
origin/daily/1.2.2
origin/daily/1.3.0
origin/daily/1.4.1
origin/develop
origin/feature/daily-1.0.0
origin/master
然后直接
git checkout origin/daily/1.4.1
就好了。。。
git branch daily/1.4.1
在切换到这个本地分支
git checkout daily/1.4.1
# Switched to branch 'daily/1.4.1'
接下来就可以去建立上游分支的关联了,但是这个命令比较长,不好记,我们可以直接先pull一下,git 会提示我们相应的操作和命令。
git pull
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.
git pull <remote> <branch>
If you wish to set tracking information for this branch you can do so with:
git branch --set-upstream-to=origin/<branch> daily/1.4.1
我们看到最后一行,执行这个命令,即可完成与上游分支的关联。
git branch --set-upstream-to=origin/daily/1.4.1 daily/1.4.1
# Branch daily/1.4.1 set up to track remote branch daily/1.4.1 from origin.
然后再pull一下就好了!
git pull
git操作