mybatis总结_mybatis中as起别名可以拼接-程序员宅基地

技术标签: java  数据库开发  mybatis  

一,概述:

就是对jdbc数据库操作进行封装,使用户开发者只用关注sql语句。通过xml或者注解的方式,将要执行的各种sql语句配置起来,并通过Java对象和statement中的sql语句映射生成最终的sql语句,最后由mybatis框架执行sql语句,并将结果映射成Java对象返回。

二. 工作原理:

1,分层:

a,接口层:接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理
b,数据处理层:SQL查找、SQL解析、SQL执行和执行结果映射处理
c,基础支撑层:功能支撑,包括连接管理、事务管理、配置加载和缓存处理

2,实现过程:

1.读取配置文件
连数据库的相关信息
2.有了这些信息就能创建SqlSessionFactory
SqlSessionFactory的生命周期是程序级,程序运行的时候建立起来,程序结束的时候消亡
3.SqlSessionFactory建立SqlSession,目的执行sql语句
SqlSession是过程级,一个方法中建立,方法结束应该关闭
4.调用MyBatis的statementHandler提供的Api执行Sql语句
5.SQL语句放在Map配置文件里面
6.执行SQl语句,不同的SQl语句返回不同的结果
1、 mybatis配置文件,包括Mybatis全局配置文件和Mybatis映射文件,其中全局配置文件配置了数据源、事务等信息;映射文件配置了SQL执行相关的 信息。
2、 mybatis通过读取配置文件信息(全局配置文件和映射文件),构造出SqlSessionFactory,即会话工厂。
3、 通过SqlSessionFactory,可以创建SqlSession即会话。Mybatis是通过SqlSession来操作数据库的。
4、 SqlSession本身不能直接操作数据库,它是通过底层的Executor执行器接口来操作数据库的。Executor接口有两个实现类,一个是普通执行器,一个是缓存执行器(默认)。
5、 Executor执行器要处理的SQL信息是封装到一个底层对象MappedStatement中。该对象包括:SQL语句、输入参数映射信息、输出结果集映射信息。其中输入参数和输出结果的映射类型包括java的简单类型、HashMap集合对象、POJO对象类型

Configuration.xml:该配置文件是MyBatis的全局配置文件,在这个文件中可以配置诸多项目,但是一般项目中,并不会配置太多内容,常用的内容是别名设置,拦截器设置等,至于环境设置与Mapper映射文件的注册会转移到Spring配置文件中(SSM整合之后),而其余大部分的配置项都采用默认的配置。
  XMLConfigBuilder:该类是XML配置构建者类,是用来通过XML配置文件来构建Configuration对象实例,构建的过程就是解析Configuration.xml配置文件的过程,期间会将从配置文件中获取到的指定标签的值逐个添加到之前创建好的默认Configuration对象实例中。
  Configuration:该类是MyBatis的配置类,创建这个类的目的就是为了使用其对象作为项目全局配置对象,这样通过配置文件配置的信息可以保存在这个配置对象中,而这个配置对象在创建好之后是保存在JVM的Heap内存中的,方便随时读取。不然每次需要配置信息的时候都要临时从磁盘配置文件中获取,代码复用性差的同时,也不利于开发。
  SqlSessionFactoryBuilder:该类是SqlSessionFactory(会话工厂)的构建者类,之前描述的操作其实全是从这里面开启的,首先就是调用XMLConfigBuilder类的构造器来创建一个XML配置构建器对象,利用这个构建器对象来调用其解析方法parse()来完成Configuration对象的创建,之后以这个配置对象为参数调用会话工厂构建者类中的build(Configuration config)方法来完成会话工厂对象的构建。
  SqlsessionFactory:该接口是会话工厂,是用来生产会话的工厂接口,DefaultSqlSessionFactory是其实现类,是真正生产会话的工厂类,这个类的实例的生命周期是全局的,它只会在首次调用时生成一个实例(单例模式),就一直存在直到服务器关闭。
  openSession():在最后的build(Configuration config)方法中会返回一个DefaultSqlSessionFactory类的实例,这个类是MyBatis提供的默认会话工厂类,而我们使用的也正是这个类中的来openSession()方法来完成SqlSession对象的创建。
  SqlSession:该接口是会话,是项目与数据库之间的会话,类似于客户端与服务器之间的会话(session),这个SqlSession的生命周期是方法级的,因为他是非线程安全的,针对每一次数据库访问都要创建一个SqlSession,获取到返回结果之后,这个SqlSession就会被废弃。这区别于SqlSessionFactory的生命周期。
  Executor:执行器接口,SqlSession会话是面向程序员的,而内部真正执行数据库操作的却是Executor执行器,可以将Executor看作是面向MyBatis执行环境的,SqlSession就是门面货,Executor才是实干家。通过SqlSession产生的数据库操作,全部是通过调用Executor执行器来完成的。
  StatementHandler:该类是Statement处理器,封装了Statement的各种数据库操作方法execute(),可见MyBatis其实就是将操作数据库的JDBC操作封装起来的一个框架,同时还实现了ORM罢了。
  ResultSetHandler:结果集处理器,如果是查询操作,必定会有返回结果,针对返回结果的操作,就要使用ResultSetHandler来进行处理,这个是由StatementHandler来进行调用的。这个处理器的作用就是对返回结果进行处理。

三,三种模式

一对一:一个成绩 一个学生

<association 表示一对多,将查询结果中 一行中的数据 设置到 对应score 对应中属性 student

【总结】:

  • association:为多表一对一的的应映射关系
  • javaType:为所用属性的java类型
<resultMap id="scoreMap1" type="score">
        <id property="scoreid" column="scoreid"></id>
        <result property="coursename" column="coursename"></result>
        <result property="score" column="score"></result>
        <result property="studentid" column="studentid"></result>

        <association property="student" javaType="student">
            <id property="id" column="studentid"></id>
            <result property="name" column="name"></result>
            <result property="age" column="age"></result>
            <result property="sex" column="sex"></result>
            <result property="height" column="height"></result>
        </association>
</resultMap>

    <select id="findAllScoreWithStudent" resultMap="scoreMap1">
            SELECT a.scoreid,a.coursename,a.score,a.studentid,b.id,b.name,b.age,b.sex,b.height FROM score_tb a LEFT JOIN student_tb b ON a.studentid = b.id
    </select>

一对多:一个学生有多个成绩

 <resultMap id="studentWithSocreMap" type="student" >

        <id property="id" column="id"></id>
        <result property="name" column="name"></result>
        <result property="age" column="age"></result>
        <result property="sex" column="sex"></result>
        <result property="height" column="height"></result>

        <collection property="scoreList" ofType="score">
            <id property="scoreid" column="scoreid"></id>
            <result property="coursename" column="coursename"></result>
            <result property="score" column="score"></result>
            <result property="studentid" column="id"></result>
        </collection>

    </resultMap>


    <select id="findAllStudentWithScore" resultMap="studentWithSocreMap" >
        SELECT a.id,a.name,a.age,a.sex,a.height,b.scoreid,b.coursename,b.score,b.studentid  FROM student_tb a LEFT JOIN score_tb b ON a.id = b.studentid
    </select>

多对多:多对多其实不存在,实际就是 两个/多个 一对多

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JbYYfQv4-1627901784025)(C:\Users\22564\AppData\Roaming\Typora\typora-user-images\image-20210611125126948.png)]

select * from role_tb r LEFT JOIN student_role_tb sr on r.id = sr.roleid
  LEFT JOIN student_tb s on sr.studentid = s.id
<resultMap id="roleMap1" type="role">
        <id property="id" column="id"></id>
        <result property="rolename" column="rolename"></result>

        <collection property="studentList" ofType="Student">
            <id property="id" column="studentid"></id>
            <result property="name" column="name"></result>
            <result property="age" column="age"></result>
            <result property="sex" column="sex"></result>
            <result property="height" column="height"></result>
        </collection>
</resultMap>

    <select id="findAllRoleWithStudent" resultMap="roleMap1">
        select r.id id,r.rolename rolename,s.name name,s.age age,s.sex sex,s.height height,sr.studentid studentid
            from role_tb r LEFT JOIN student_role_tb sr on r.id = sr.roleid
                LEFT JOIN student_tb s on sr.studentid = s.id
    </select>

(1)事务模块,抽象工厂模式
(2)数据源:数据源接口中定义了两个获取数据库连接Connection的方法,可见数据源的目的所在,不论其使用什么原理实现,其目的就是为了对外提供数据库连接的获取接口。unpooled:非池型数据源。pooled:同步的线程安全的池型数据源。jndi:托管型

四,问题:

1,#{}和${}的区别是什么?

{}是预编译处理,${}是字符串替换。
Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
Mybatis在处理时,就是把时,就是把{}替换成变量的值。
使用#{}可以有效的防止SQL注入,提高系统安全性。

2,当实体类中的属性名和表中的字段名不一样 ,怎么办

第1种: 通过在查询的sql语句中定义字段名的别名,让字段名的别名和实体类的属性名一致
第2种: 通过来映射字段名和实体类属性名的一一对应的关系

3,通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?

Dao接口,就是人们常说的Mapper接口,接口的全限名,就是映射文件中的namespace的值,接口的方法名,就是映射文件中MappedStatement的id值,接口方法内的参数,就是传递给sql的参数。Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为key值,可唯一定位一个MappedStatement,举例:com.mybatis3.mappers.StudentDao.findStudentById,可以唯一找到namespace为com.mybatis3.mappers.StudentDao下面id = findStudentById的MappedStatement。在Mybatis中,每一个标签,都会被解析为一个MappedStatement对象。

Dao接口里的方法,是不能重载的,因为是全限名+方法名的保存和寻找策略。

Dao接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao接口生成代理proxy对象,代理对象proxy会拦截接口方法,转而执行MappedStatement所代表的sql,然后将sql执行结果返回。

4,Mybatis是如何进行分页的

Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页,可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。

5,在mapper中如何传递多个参数

对应的xml,#{0}代表接收的是dao层中的第一个参数,#{1}代表dao层中第二参数,更多参数一致往后加即可,

在mybatis 中 如果有多个参数 并且使用 #{参数名} 必须在方法中为参数声明 别名 @Param(“sex”)

也可以使用 arg0 arg1 或者 param1 param2
* 如果是传多个属性(参数)
* 也可以直接传对象
* findStudentBySexAndAge(Student student);
* 或者直接传对象
* findStudentBySexAndAge(Map map);

 findStudentBySexAndAge(@Param("sex") String sex,@Param("age") int age);
6,缓存问题:

缓存:比如执行select * from student 第一次,sqlsesion 没有缓存去数据库找,缓存起来,第二次执行select * from student 直接去缓存找。Mybatis在查询时会采用缓存机制,分为一级缓存和二级缓存,

好处:1.查询效率高(快)2.降低mysql服务器请求查询压力

mybatis 一级二级缓存

一级缓存就是基于sqlsesion 的缓存

二级缓存基于namespace的缓存,二级缓存是 多个 sqlsesion 共享的

一级缓存默认就会开启,二级缓存需要配置才可以使用。无论是一级缓存,还是二级缓存共同的特点:所有的查询都会缓存,但是只要发生增删改,缓存立即清空否则会有脏数据问题。
一级缓存:一级缓存是 SqlSession 级别的缓存,只要 SqlSession 没有 flush 或 close,它就存在。一旦发生增删改,缓存立即失效。
二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache、Hazelcast等。
对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。
在缓存的作用域中,如果调用的方法的参数一样,就会使用缓存中查询的结果,而不会再次查询数据库。

二级缓存:基于namespace,有多个Sqlsession共享

二级缓存开启:

1、开启缓存开关

<settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>

        <!-- 开启全局懒加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>

        <!--开启二级缓存-->
        <setting name="cacheEnabled" value="true"/>

</settings>

2、对应的dao.xml开启缓存

<!--
         <cache>  开启二级缓存
            eviction="LRU" 缓存是有大小限制,超过大小要 清除一些缓存
                    - LRU - 最近最少回收,移除最长时间不被使用的对象
                    - FIFO - 先进先出,按照缓存进入的顺序来移除它们
                    - SOFT - 软引用,移除基于垃圾回收器状态和软引用规则的对象
                    - WEAK - 弱引用,更积极的移除基于垃圾收集器和弱引用规则的对象
            size="1024"  缓存 最多 1024 条数 sql 对应的数据
            flushInterval="60000"  60s 缓存 刷新一次
            readOnly="true" 是否只读  不能获取缓存中对象的引用,不能直接修改缓存对象
                     "false" 能获取缓存中对象的引用,能直接修改缓存对象
                      
            blocking="true" 在读取缓存时是否阻塞 
    -->
<cache eviction="LRU" size="1024" flushInterval="60000" readOnly="true" blocking="true">
</cache>

3、使用缓存

<!--
        在查选标签中配置 useCache="true" 使用缓存
        默认值就是true 使用缓存    
-->
<select id="findStudentById" resultType="Student" useCache="true">
        select  * from student_tb where id = #{id}
</select>

【注意】:一级缓存和二级缓存同时存在,可能会引入脏数据

【解决方案】:

1、第一种不使用一级缓存

<!-- 将一级缓存修改为STATEMENT表示不使用一级缓存
                  SESSION表示使用一级缓存
-->
<setting name="localCacheScope" value="STATEMENT"/>

2、在spring中使用mybatis,每次调用mapper对应的方法,都使用新的Sqlsession

7、Mybatis基于注解的开发
public interface StudentDao{
    

    @Select("select * from student_tb where id = #{id}")
    Student findStudentById(int id);

    @Insert("insert into student_tb (name,age,sex,height) values(#{name},#{age},#{sex},#{height})")

    @SelectKey(resultType = Integer.class,keyProperty = "id",keyColumn = "id",before = false,statement = "select last_insert_id()")
	//获取自增id  statement = "" 获取自增id 的sql
    int addStudent(Student student);

    @Update("update student_tb set name = #{name},age = #{age},sex=#{sex},height=#{height} where id = #{id}")
    int updateStudent(Student student);

    @Delete("delete from student_tb where id = #{id}")
    int deleteStudent(int id);

}

自定义resultMap完成数据库列名和实体类名不一致的问题

@Results

@Select("select * from student_tb")
@Results(id = "studentResult1",value = {
        @Result(id = true,property = "id",column = "id"),
        @Result(property = "name",column = "name"),
        @Result(property = "age",column = "age"),
        @Result(property = "sex",column = "sex"),
        @Result(property = "height",column = "height")
    })// 相当于xml 中 <resultMap> 声明map
    // @Result(id = true,property = "id",column = "id") 相当于 <id property="id" column="id"></id>
    List<Student> findAllStudent();

    @Select("select * from student_tb where sex = #{sex}")
    @ResultMap(value = "studentResult1")// 使用@ResultMap 引用已经在其他方法上声明的 		@Results
    List<Student> findAllStudentBySex(String sex);

基于注解的懒加载

@Select("select * from student_tb")
@Results(id = "studentResult2",value = {
			@Result(id = true,property = "id",column = "id"),
            @Result(property = "name",column = "name"),
            @Result(property = "age",column = "age"),
            @Result(property = "sex",column = "sex"),
            @Result(property = "height",column = "height"),
            @Result(property = "scoreList",column = "id",many = @Many(select = "com.qfedu.dao.ScoreDao.findAllScoreByStudentId",fetchType = FetchType.LAZY))
    })
    List<Student> findAllStudentWithScorelazy();
9,延迟加载:

延迟加载就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.

好处: 先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。

坏处: 因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗。

1、开启懒加载:

<settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>

        <!-- 开启全局懒加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>

    </settings>

2、一对多懒加载:

 <!--

        一对多懒加载
            column="id" 两张表关联的id

            select="com.qfedu.dao.ScoreDao.findAllScoreByStudentId"  调用 更具学生id 查询所有成绩方法

             fetchType="lazy" 懒加载
             fetchType="eager" 立即加载
    -->
    <resultMap id="studentMap1" type="Student">
        <id property="id" column="id"></id>
        <result property="name" column="name"></result>
        <result property="age" column="age"></result>
        <result property="sex" column="sex"></result>
        <result property="height" column="height"></result>

        <collection property="scoreList" ofType="Score" column="id" select="com.qfedu.dao.ScoreDao.findAllScoreByStudentId"
                    fetchType="lazy">
        </collection>
    </resultMap>

    <select id="findStudentByLazy" resultMap="studentMap1">
        select  * from  student_tb
    </select>
10、PageHelper分页

pagehelper 是mybatis 的一个插件,帮助我们完成分页查询

1、引入依赖

<!--配置分页-->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>4.1.4</version>
</dependency>

2、在配置文件中引入

<!--
   配置pagehelper 插件注意  必须在 <environments 之前
-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <!-- 使用MySQL方言的分页 -->
            <property name="helperDialect" value="mysql"/><!--如果使用mysql,这里value为mysql-->
            <!--  
                如果 pegesize为0 查询所有
            -->
            <property name="pageSizeZero" value="true"/>
        </plugin>
    </plugins>

3、使用

 @Test
    public void pageHelperTest(){

        // PageHelper 帮助 下面的 sql 完成分页
        // 在 select * from student_tb  拼接 limit index,pagesize
//        select * from student_tb limit ?,?
        PageHelper.startPage(1, 3);// 在查选语句之前 调用

        List<Student> allStudentList = studentDao2.findAllStudent();

        // 获取分页信息
        PageInfo<Student> pageInfo = new PageInfo<Student>(allStudentList);

        System.out.println("总数量"+pageInfo.getTotal());
        System.out.println("当前页"+pageInfo.getPageNum());
        System.out.println("每页多少"+pageInfo.getPageSize());
        System.out.println("总页数"+pageInfo.getPages());

        for (Student student : allStudentList) {
            System.out.println("student:"+student);
        }

    }
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Key_finger/article/details/119331798

智能推荐

leetcode 172. 阶乘后的零-程序员宅基地

文章浏览阅读63次。题目给定一个整数 n,返回 n! 结果尾数中零的数量。解题思路每个0都是由2 * 5得来的,相当于要求n!分解成质因子后2 * 5的数目,由于n中2的数目肯定是要大于5的数目,所以我们只需要求出n!中5的数目。C++代码class Solution {public: int trailingZeroes(int n) { ...

Day15-【Java SE进阶】IO流(一):File、IO流概述、File文件对象的创建、字节输入输出流FileInputStream FileoutputStream、释放资源。_outputstream释放-程序员宅基地

文章浏览阅读992次,点赞27次,收藏15次。UTF-8是Unicode字符集的一种编码方案,采取可变长编码方案,共分四个长度区:1个字节,2个字节,3个字节,4个字节。文件字节输入流:每次读取多个字节到字节数组中去,返回读取的字节数量,读取完毕会返回-1。注意1:字符编码时使用的字符集,和解码时使用的字符集必须一致,否则会出现乱码。定义一个与文件一样大的字节数组,一次性读取完文件的全部字节。UTF-8字符集:汉字占3个字节,英文、数字占1个字节。GBK字符集:汉字占2个字节,英文、数字占1个字节。GBK规定:汉字的第一个字节的第一位必须是1。_outputstream释放

jeecgboot重新登录_jeecg 登录自动退出-程序员宅基地

文章浏览阅读1.8k次,点赞3次,收藏3次。解决jeecgboot每次登录进去都会弹出请重新登录问题,在utils文件下找到request.js文件注释这段代码即可_jeecg 登录自动退出

数据中心供配电系统负荷计算实例分析-程序员宅基地

文章浏览阅读3.4k次。我国目前普遍采用需要系数法和二项式系数法确定用电设备的负荷,其中需要系数法是国际上普遍采用的确定计算负荷的方法,最为简便;而二项式系数法在确定设备台数较少且各台设备容量差..._数据中心用电负荷统计变压器

HTML5期末大作业:网页制作代码 网站设计——人电影网站(5页) HTML+CSS+JavaScript 学生DW网页设计作业成品 dreamweaver作业静态HTML网页设计模板_网页设计成品百度网盘-程序员宅基地

文章浏览阅读7k次,点赞4次,收藏46次。HTML5期末大作业:网页制作代码 网站设计——人电影网站(5页) HTML+CSS+JavaScript 学生DW网页设计作业成品 dreamweaver作业静态HTML网页设计模板常见网页设计作业题材有 个人、 美食、 公司、 学校、 旅游、 电商、 宠物、 电器、 茶叶、 家居、 酒店、 舞蹈、 动漫、 明星、 服装、 体育、 化妆品、 物流、 环保、 书籍、 婚纱、 军事、 游戏、 节日、 戒烟、 电影、 摄影、 文化、 家乡、 鲜花、 礼品、 汽车、 其他 等网页设计题目, A+水平作业_网页设计成品百度网盘

【Jailhouse 文章】Look Mum, no VM Exits_jailhouse sr-iov-程序员宅基地

文章浏览阅读392次。jailhouse 文章翻译,Look Mum, no VM Exits!_jailhouse sr-iov

随便推点

chatgpt赋能python:Python怎么删除文件中的某一行_python 删除文件特定几行-程序员宅基地

文章浏览阅读751次。本文由chatgpt生成,文章没有在chatgpt生成的基础上进行任何的修改。以上只是chatgpt能力的冰山一角。作为通用的Aigc大模型,只是展现它原本的实力。对于颠覆工作方式的ChatGPT,应该选择拥抱而不是抗拒,未来属于“会用”AI的人。AI职场汇报智能办公文案写作效率提升教程 专注于AI+职场+办公方向。下图是课程的整体大纲下图是AI职场汇报智能办公文案写作效率提升教程中用到的ai工具。_python 删除文件特定几行

Java过滤特殊字符的正则表达式_java正则表达式过滤特殊字符-程序员宅基地

文章浏览阅读2.1k次。【代码】Java过滤特殊字符的正则表达式。_java正则表达式过滤特殊字符

CSS中设置背景的7个属性及简写background注意点_background设置背景图片-程序员宅基地

文章浏览阅读5.7k次,点赞4次,收藏17次。css中背景的设置至关重要,也是一个难点,因为属性众多,对应的属性值也比较多,这里详细的列举了背景相关的7个属性及对应的属性值,并附上演示代码,后期要用的话,可以随时查看,那我们坐稳开车了······1: background-color 设置背景颜色2:background-image来设置背景图片- 语法:background-image:url(相对路径);-可以同时为一个元素指定背景颜色和背景图片,这样背景颜色将会作为背景图片的底色,一般情况下设置背景..._background设置背景图片

Win10 安装系统跳过创建用户,直接启用 Administrator_windows10msoobe进程-程序员宅基地

文章浏览阅读2.6k次,点赞2次,收藏8次。Win10 安装系统跳过创建用户,直接启用 Administrator_windows10msoobe进程

PyCharm2021安装教程-程序员宅基地

文章浏览阅读10w+次,点赞653次,收藏3k次。Windows安装pycharm教程新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入下载安装PyCharm1、进入官网PyCharm的下载地址:http://www.jetbrains.com/pycharm/downl_pycharm2021

《跨境电商——速卖通搜索排名规则解析与SEO技术》一一1.1 初识速卖通的搜索引擎...-程序员宅基地

文章浏览阅读835次。本节书摘来自异步社区出版社《跨境电商——速卖通搜索排名规则解析与SEO技术》一书中的第1章,第1.1节,作者: 冯晓宁,更多章节内容可以访问云栖社区“异步社区”公众号查看。1.1 初识速卖通的搜索引擎1.1.1 初识速卖通搜索作为速卖通卖家都应该知道,速卖通经常被视为“国际版的淘宝”。那么请想一下,普通消费者在淘宝网上购买商品的时候,他的行为应该..._跨境电商 速卖通搜索排名规则解析与seo技术 pdf

推荐文章

热门文章

相关标签