MyBatis 持久化框架快速使用入门(Xml配置版)
目录
MyBatis 持久化框架概述
Mybatis 标签汇总
SqlSessionFactory & SqlSession
搭建 Spring boot + Mybatis 环境
MyBatis 语法使用快速入门
resultType 设置查询结果类型
parameterType 设置参数类型
#{} VS ${} 取值对比
[CDATA[XXX]]> 转义小于符号
foreach 循环容器元素
concat 字符串拼接
choose (when, otherwise) 流程控制
if 条件判断
where 条件语句
if + set 修改语句
trim 代替 where、set 标签
sql 片段标签定义 sql 片段
MyBatis 集成 Spring boot 自动配置原理
@Param 定义 XxxMapper 方法多个参数
本文环境:Spring boot 2.3.5 + Java jdk 8 + Mysql + Log4j2 . + MyBatis 3.5.7
1、用户访问 Controller 控制层 -> Servires 业务层-> XxxMapper 接口-> XxxMapper.xml 映射。
2、所以使用 MyBatis 的重点就是 XxxMapper 接口 与 XxxMapper.xml 映射,本文采用 xml 的方式,不采用在注解上写 Sql 的方式。
MyBatis 持久化框架概述
1、MyBatis 是世界上流行最广泛的 SQL 映射框架之一。
官网:https://blog.mybatis.org/ MyBatis中文官网:https://github.com/mybatis/mybatis-3 配置:https://mybatis.org/mybatis-3/configuration.html#settings 集成:http://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/ github:https://github.com/mybatis/mybatis-3 |
2、Hibernate 的优点是将整个开发设计过程全部面向对象开发,全ORM,不用写任何SQL语句。
3、MyBatis 维持原有的编程方式,前部分按面向对象思考和设计,持久层时使用sql语句,面向过程,半 ORM。
4、Hibernate 的弱点是底层仍然使用sql,需要将hql语句转为sql,导致Sql无法优化,且Hibernate需要通过反射,性能较低。
5、MyBatis 只是基于jdbc的轻量级封装,还是使用sql,性能比较高。
6、所以业内认为:中小型项目使用 Hibernate,开发速度快;大型项目使用MyBatis,项目性能高。
7、 SqlSessionFactory 是线程安全的,SqlSession是线程不安全的,不能做类的公共变量。
8、学习 MyBatis 主要是学习它的标签语法,它们很类似以前的 JSTL 标签,所以本文重点就是介绍它的语法使用。
Mybatis 标签汇总
常用标签 | 描述 |
---|---|
<select> | 用于 select 查询 sql 语句 |
<insert> | 用于 insert 插入 sql 语句 |
<update> | 用于 update 更新 sql 语句 |
<delete> | 用于 delete 删除 sql 语句 |
<foreach> | 用于遍历容器元素,如 List、Set、Array 等,通常用于为 in 函数设置参数. |
<![CDATA[xxx]]> |
小于符号转义,如 <![CDATA[and sal <= #{end}]]> |
<mapper namespace="xxx"> | mapper 是整个 xml 文件的根标签,namespace 表示此配置文件的命名空间,严格上来说,没有强制要求,只需要唯一即可,不过官方推荐命名空间设置为 XxxMapper 的全路径. |
<if test=true|false> |
如果判断结果为 true,则将其中的内容拼接到 sql 中,否则不拼接。 |
<where> |
当 where 标签中有返回值时,where 标签会自动插入一个 'where' 字符串 sql . |
<set> | 当其中有内容时,自动添加 set 关键字,如果内容结尾有多余的逗号,也会自动删除。 |
<trim> |
trim 是一个格式化的标记,可以完成 set、where 标记的功能,有如下属性: prefix:为内容添加前缀,如 "set" suffix:为内容添加前缀,如 "where id=#{id}" suffixOverrides:去掉内容结尾的指定字符串(多个时用"|"隔开),如逗号 "," prefixOverrides:去掉内容开头的指定字符串(多个时用"|"隔开),如逗号 "and|or" |
SqlSessionFactory & SqlSession
MyBatis 核心API | 描述 |
---|---|
SqlSessionFactoryBuilder |
a、这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。因此 SqlSessionFactoryBuilder 实例的最佳范围是方法范围(也就是本地方法变量)。 b、可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但是最好还是不要让其一直存在以保证所有的 XML 解析资源开放给更重要的事情。 |
SqlSessionFactory |
a、一旦被创建就应该在应用的运行期间一直存在,没有任何理由对它进行清除或重建。使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次。 b、因此 SqlSessionFactory 的最佳范围是应用范围,有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。 |
openSession():会默认开启一个事务,但事务不会自动提交,需要手动提交和回滚。 openSession(boolean autoCommit):参数为是否自动提交,如果设置为true。 |
|
SqlSession |
a、每个线程都应该有它自己的 SqlSession 实例,SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的范围是请求或方法范围。 b、绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例域也不行。也绝不能将 SqlSession 实例的引用放在任何类型的管理范围中,比如 Serlvet 架构中的 HttpSession。换句话说,每次收到的 HTTP 请求,就可以打开一个 SqlSession,返回一个响应,就关闭它。这个关闭操作是很重要的,应该把这个关闭操作放到 finally 块中以确保每次都能执行关闭。 |
9、如下所示为纯 MyBatis 底层用法,如果是 myBatis + Sring Boot 集成,则无法在编写这种底层代码了。
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession= sqlSessionFactory.openSession();
try {BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);// do worksqlSession.commit();
} catch(Exception e){sqlSession.rollback();
} finally {session.close();
}
搭建 Spring boot + Mybatis 环境
1、新建 Spring boot 应用,pom.xml 文件引入相关依赖,比如 log4j2 日志、mysql 驱动、myBatis:https://gitee.com/wangmx1993/hb/blob/master/pom.xml
2、Mysql 数据库中准备好数据库、表、以及测试数据:创建 emp 与 dept 脚本.sql
3、类路径下提供 log4j2 日志配置文件:src/main/resources/log4j2.xml · 汪少棠/hb - Gitee.com
为了能清晰的看到 myBatis 执行的 sql,可以设置 myBatis 的日志输出基本为 debug:
<logger name="org.mybatis" level="debug"></logger>
4、application.yml 全局配置文件配置数据源与 myBatis:src/main/resources/application.yml · 汪少棠/hb - Gitee.com
5、提供 myBatis 核心配置文件: mybatis-config
6、jdbc 默认使用的 Hikari 数据源,可以写一个测试类 DataBaseTests 运行一下,看看数据库是否连接正常,此时需要先将 application.yml 中 myBatis 的配置暂时注释掉。
7、为了更好的封装接口返回的参数,提供返回数据实体和枚举:ResultData.java、ResultCode.java。
8、提供全局统一异常处理类:AppExceptionController.java
9、本文的 XxxMapper 映射接口在线源码目录:https://gitee.com/wangmx1993/hb/blob/master/src/main/java/com/wmx/hb/mapper
10、本文的 XxxMapper.xml 映射在线源码目录:/src/main/resources/myBatis/mapper
MyBatis 语法使用快速入门
resultType 设置查询结果类型
1. resultType 是 <select> 标签中的属性,表示查询结果的类型。
2. resultType 的值可以是基础类型,如 int、String;也可以是 POJO 对象,如 User,POJO 对象时要写全路径。
<!--查询表中的数据总条数-->
<select id="countForTable" resultType="long">select count(1) from dept
</select><!--返回值类型指定为 List 中的元素类型-->
<select id="findDeptEmp" resultType="java.util.Map">SELECT t1.*,t2.* from dept t1,emp t2 WHERE t1.deptno = #{deptno} and t1.deptno = t2.deptno;
</select><!-- select 表示查询标签,id 属性值是 DeptMapper 接口中的方法名称,resultType 指定返回值的类型-->
<!--可以不指定 parameterType 属性,此时会自动根据接口方法的参数类型进行映射-->
<select id="findDeptById" resultType="com.wmx.hb.pojo.Dept">select dept.deptno,dept.dname,dept.loc from dept where deptno = #{deptno}
</select>
parameterType 设置参数类型
1、parameterType 是 CRUD 标签中的属性,表示参数类型、参数映射,可以省略不写,此时会自动根据接口方法的参数进行映射。
2、parameterType 同样可以是基本数据类型如:int、flout等;也可以是POJO对象;甚至是List、Set、Array、Map等。
3、因为 Map 最灵活,所以项目中一般用 Map 最多,#{key} 取值的 key 就是 Map 中的 key。使用示例看下一节。
#{} VS ${} 取值对比
1、两者都是用于获取传入的参数值。
#{}表示一个占位符号,通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java类型和 jdbc 类型转换,#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。 | ${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。 |
2、#{}:会自动根据参数类型做封装,例如对字符串、日期类型,两边自动加单引号,而对数值类型直接使用。
3、${}:将传入的参数直接拼接到 SQL 中,例如拼接 order by xxx ,这是比较特殊的地方,也是 #{} 唯一无法做到的地方。
4、#{} 的好处是可以防止 SQL注入,因为非法用户传入的非法SQL只能是字符串类型,这样两头加上单引号后,SQL语法就错了,不会执行成功的()。
5、${} 取的值如果为 null,还容易报错,所以除非不得已,否则推荐一律使用 #{}。
//分页查询接口
@GetMapping("/dept/findByLimit")
public ResultData<List<Dept>> findByLimit(Integer page, Integer rows) {page = page == null || page <= 0 ? 1 : page;rows = rows == null || rows <= 0 ? 2 : rows;Map<String, Object> paramMap = new HashMap<>();paramMap.put("start", (page - 1) * rows);paramMap.put("end", (page - 1) * rows + rows);paramMap.put("orderColumn","dname");List<Dept> deptList = deptMapper.findByLimit(paramMap);return new ResultData<>(ResultCode.SUCCESS, deptList, null, page, rows);
}//deptMapper 映射接口方法
List<Dept> findByLimit(Map<String, Object> paramMap);<!--DeptMapper.xml 标签-->
<!-- 可以不指定 parameterType 属性,此时会自动根据接口方法的参数类型进行映射-->
<!-- order by 的值必须使用 ${} 取值}-->
<select id="findByLimit" resultType="com.wmx.hb.pojo.Dept" parameterType="map">select dept.deptno,dept.dname,dept.loc from dept order by ${orderColumn} limit #{start},#{end}
</select>
//比如想根据某列的值进行查询,其中 ${column} 会被直接替换,如 id,name,age...,而 #{value} 会使用 ? 预处理
//用这种方式接受用户的输入,并用作语句参数是不安全的,会导致潜在的 SQL 注入攻击,
//因此,要么不允许用户输入这些字段(column),要么自行转义并检验这些参数。
@Select("select * from user where ${column} = #{value}")
List<User> findByColumn(String column, String value);
[CDATA[XXX]]> 转义小于符号
1、小于符号'<' 在 xml 文件中表示标签的开始,所以 sql 中的小于符号必须进行转义。
//查询薪资在[start,end]之间的员工,start 为空时,不设下限,end 为空时,不设上限.
@GetMapping("/emp/getEmpBySal")
public ResultData<Emp> getEmpBySal(Double start, Double end) {Map<String, Double> paramMap = new HashMap<>();paramMap.put("start", start);paramMap.put("end", end);List<Emp> empList = empMapper.getEmpBySal(paramMap);return new ResultData(ResultCode.SUCCESS, empList);
}//EmpMapper 接口方法
List<Emp> getEmpBySal(Map<String, Double> paramMap);<!--EmpMapper.xml 映射:小于符号'<'必须进行转义-->
<select id="getEmpBySal" resultType="com.wmx.hb.pojo.Emp" parameterType="map">select * from emp t<where><if test="start!=null">sal >= #{start}</if><if test="end != null"><![CDATA[and sal <= #{end}]]></if></where>
</select>
foreach 循环容器元素
1、foreach 元素的属性主要有:item,index,collection,open,separator,close
item:集合中元素迭代时的别名
index:集合中元素迭代时的索引
open:常用语where语句中,表示以什么开始,比如以'('开始
separator:表示在每次进行迭代时的分隔符,比如','
close:常用语where语句中,表示以什么结束,比如以')'结尾
collection:集合名称,通常是集合或者数组的参数名称,必传,其他的选项可选
2、collection 属性是必须指定的,在不同情况下,其值是不一样的,主要有以下3种情况:
如果传入的是单参数且参数类型是一个List的时候,collection属性值为list.
如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array.
如果传入的参数是多参数,则需要把它们封装成一个Map,当然单参数也可以封装成map.
3、不管是多参数还是单参数的 list,array,set类型,collection 都可以封装为map进行传递。
如果传递的是一个List,则mybatis会封装为一个list为key,list值为object的map,
如果是array,则封装成一个array为key,array的值为object的map,
如果自己封装呢,则colloection里放的是自己封装的map里的key值
4、注意 foreach 的集合或者数组如果为空,则抛异常。
//mapper 接口中提供方法:根据主键集合查询部门数据
List<Dept> findByDeptnos(List<Integer> deptnos);!--根据主键 id集合查询,deptnos 就是接口方法参数的名称,如果 foreach 的集合或者数组为空,则直接异常-->
<select id="findByDeptnos" resultType="com.wmx.hb.pojo.Dept">select * from dept<where><if test="deptnos !=null and deptnos.size > 0">deptno in<foreach collection="deptnos" item="deptno" index="index" open="(" separator="," close=")">#{deptno}</foreach></if></where>
</select>
concat 字符串拼接
1、concat 元素类似数据库的 concat 函数,用于拼接字符串.
//mapper 接口中提供方法:根据关键字模糊查询,默认查询所有
List<Dept> findByKeyword(String keyword);<!-- 对应 xml 中标签:根据关键字模糊查询,不为空时才拼 like 条件,否则默认查询所有.-->
<select id="findByKeyword" resultType="com.wmx.hb.pojo.Dept" parameterType="string">select * from dept<where><if test="keyword!=null">dname like concat('%',concat(#{keyword},'%')) or loc like concat('%',concat(#{keyword},'%'))</if></where>
</select>
choose (when, otherwise) 流程控制
1、choose 标签是按顺序判断其内部 when 标签中的 test 条件是否成立,如果有一个成立,则 choose 结束,其他的 when 以及 otherwise 都不会再走。
2、当 choose 中所有 when 的条件都不满足时,则执行 otherwise 中的 sql。
//mapper 接口中提供方法:按顺序将实体类 Emp 第一个不为空的属性作为 where 查询条件,默认查所有
List<Emp> getEmp(Emp emp);<!--对应 xml 中标签:choose-when-otherwise,其中一个 when 条件成立,则其他的都不会再走,所有 when 都不成立时,走 otherwise-->
<!-- select 表示查询标签,id 属性值是 XxxMapper 接口中的方法名称,resultType 指定返回值的类型-->
<!--可以不指定 parameterType 属性,此时会自动根据接口方法的参数类型进行映射-->
<select id="getEmp" resultType="com.wmx.hb.pojo.Emp" parameterType="com.wmx.hb.pojo.Emp">select * from emp<where><choose><when test="empno !=null">empno=#{empno}</when><when test="ename !=null and ename !=''">ename like concat('%',concat(#{ename},'%'))</when><when test="job !=null and job !=''">job like concat('%',concat(#{job},'%'))</when><when test="hiredate !=null">hiredate=#{hiredate}</when><otherwise></otherwise></choose></where>
</select>
if 条件判断
1、myBatis 中很多标签,如果参数为空,或者为 null,则容易出现异常,比如 foreach 的集合或者数组为空,则直接异常。
2、此时可以使用 if 动态 sql 语句先进行判断,如果值为 null 或等于空字符串,或者集合的 size<=0,则不进行操作。
where 条件语句
1、当 where 标签中有返回值时,where 标签会自动插入一个 'where' 字符串 sql .
2、当 where 标签返回的内容是以 AND 或 OR 开头,则会自动剔除掉 'and' 和 'or',不区分大小写。
//mapper 接口中提供方法:查询指定部门的信息,将实体对象中不为空的属性都作为 where 条件,默认查所有
List<Dept> findByDept(Dept dept);<!--对应 xml 中标签:拼接 where 条件前进行是否为空判断-->
<!--where 标签会自动删除内容开头的 and 或者 or 字符串 -->
<select id="findByDept" resultType="com.wmx.hb.pojo.Dept">SELECT t1.deptno,t1.dname,t1.loc from dept t1<where><if test="deptno!=null">deptno = #{deptno}</if><if test="dname!=null and dname !=''">and dname like concat('%',concat(#{dname},'%'))</if><if test="loc!=null and loc!=''">and loc like concat('%',concat(#{loc},'%'))</if></where>
</select>
if + set 修改语句
1、当在 update 语句中使用 if 标签时,如果后面的 if 没有执行,则结尾会产生多余的逗号,从而导致错误。
2、使用 set 标签可以动态的追加 SET 关键字,以及剔除追加到条件末尾的任何多余的逗号。
//mapper 接口中提供方法:根据主键id修改部门信息,只修改不为null,且不为空的属性
Integer updateDeptByNotNull(Dept dept);<!--对应 xml 中标签:set标签会自动去除内容结尾多余的逗号-->
<update id="updateDeptByNotNull" parameterType="com.wmx.hb.pojo.Dept">update dept t<set><if test="dname!=null and dname !=''">dname=#{dname},</if><if test="loc!=null and loc!=''">loc=#{loc}</if></set>where deptno=#{deptno}
</update>
trim 代替 where、set 标签
1、trim 是更灵活的去处多余关键字的标签,可以代替 where 和 set 标签。
prefix:表示为内容添加前缀,比如 where
suffix:表示为内容添加后缀
prefixOverrides:表示前缀覆盖,去除内容开头多余的前缀,如 'and'、'or'
suffixOverrides:表示后缀覆盖,去除内容结尾多余的后缀,如 ','
2、trim标签代替 where标签,prefix 表示添加前缀 where,prefixOverrides 表示前缀覆盖,去除内容开头多余的 and 或者 or。
<!--trim标签代替 where标签,prefix 表示添加前缀 where,prefixOverrides 表示前缀覆盖,去除前缀多余的 and 或者 or--><select id="loadByDept" resultType="com.wmx.hb.pojo.Dept">SELECT t1.deptno,t1.dname,t1.loc from dept t1<trim prefix="where" prefixOverrides="and|or"><if test="deptno!=null">deptno = #{deptno}</if><if test="dname!=null and dname !=''">and dname like concat('%',concat(#{dname},'%'))</if><if test="loc!=null and loc!=''">and loc like concat('%',concat(#{loc},'%'))</if></trim></select>
3、trim 标签代替 set 标签,prefix 表示添加前缀 set,suffixOverrides 表示后缀覆盖,去除内容结尾多余的逗号
<!--trim标签代替 set 标签,prefix 表示添加前缀 set,suffixOverrides 表示后缀覆盖,去除内容结尾多余的逗号--><update id="modifyDeptByNotNull" parameterType="com.wmx.hb.pojo.Dept">update dept t<trim prefix="set" suffixOverrides=","><if test="dname!=null and dname !=''">dname=#{dname},</if><if test="loc!=null and loc!=''">loc=#{loc}</if></trim>where deptno=#{deptno}</update>
sql 片段标签定义 sql 片段
1、sql 片段标签 <sql> 可定义能复用的 sql 语句片段,在执行 sql 语句标签中直接引用即可。
2、<sql> 的属性 id="xxx" 值表示该 sql 语句片段的唯一标识.
3、引用 sql 片段:通过 <include refid="xxx" /> 标签引用,refid="" 中的值指向需要引用的<sql>中的id属性。
<!--定义 dept 表的列信息,查询标签可以直接引用,不用再每次都重复写一遍-->
<sql id="dept_columns">dept.deptno,dept.dname,dept.loc
</sql><!-- 查询所有,虽然返回值是一个 List<Dept>,但是 resultType 只需要指定列表元素的类型即可.-->
<!--include 引用定义好的 sql 片段-->
<select id="findAllDepts" resultType="com.wmx.hb.pojo.Dept">select <include refid="dept_columns"/> from dept;
</select>
MyBatis 集成 Spring boot 自动配置原理
Spring Boot 2.x 集成 MyBatis ,MyBatis 自动配置原理与自定义配置
@Param 定义 XxxMapper 方法多个参数
1、XxxMapper 接口方法中如果需要使用到多个参数,通常是封装成 POJO 对象,或者使用 Map 封装,而 Map 看起来不太直观,此时可以使用 myBatis 的 @Param 注解进行定义。
//控制层方法
@PostMapping("/findByDept")
public List<Dept> findByDept(@RequestBody(required = false) Dept dept, Integer pageNum, Integer pageSize) {pageNum = pageNum == null || pageNum <= 0L ? 1 : pageNum;pageSize = pageSize == null || pageSize <= 0L ? 2 : pageSize;List<Dept> deptList = deptMapper.findByDept(dept, pageNum, pageSize);return deptList;
}/**DeptMapper 接口方法* 1、查询指定部门的信息,将实体对象中不为空的属性都作为 where 条件,默认查所有。* 2、使用 org.apache.ibatis.annotations.Param 注解可以为 XxxMapper 接口方法指定多个参数。* 3、多个参数会被封装成一个 map,map 的 key 是使用 @Param 注解指定的值,value 是参数值。* 4、如果是级联对象,则 XxxMapper.xml 映射文件中也是级联取值,如 dept.deptno、dept.dname,前提是 dept 不能为 null,否则异常.* * @param dept* @param pageNum :查询的页码,从1开始* @param pageSize :每页显示的条数* @return*/
List<Dept> findByDept(@Param("dept") Dept dept, @Param("pageNum") int pageNum, @Param("pageSize") int pageSize);<!--dept是对象,所以需要级联取值,必须不等于 null,才能级联取值-->
<!--拼接 where 条件前进行参数是否为空判断。返回值类型指定为 List 中的元素类型-->
<!--where 标签会自动删除内容开头的 and 或者 or 字符串 -->
<select id="findByDept" resultType="com.wmx.hb.pojo.Dept">SELECT t1.deptno,t1.dname,t1.loc from dept t1<where><if test="dept !=null and dept.deptno!=null">deptno = #{dept.deptno}</if><if test="dept !=null and dept.dname!=null and dept.dname !=''">and dname like concat('%',concat(#{dept.dname},'%'))</if><if test="dept !=null and dept.loc!=null and dept.loc!=''">and loc like concat('%',concat(#{dept.loc},'%'))</if></where>
</select>
MyBatis 持久化框架快速使用入门(Xml配置版)相关推荐
- 第 3-2 课:SpringBoot如何优雅地使⽤ MyBatis XML 配置版
MyBatis 是现如今最流⾏的 ORM 框架之⼀,我们先来了解⼀下什么是 ORM 框架. ORM 框架 对象关系映射(Object Relational Mapping,ORM)模式是⼀种为了解决⾯ ...
- 【SpringMVC 笔记】SpringMVC 原理 + 入门项目(xml 配置版 vs 注解版)
SpringMVC 入门项目 什么是 SpringMVC? 中心控制器 SpringMVC 执行原理 执行流程 xml 配置版 1.创建一个 Web 项目 2.pom.xml 中导入 SpringMV ...
- Spring Boot入门系列(六)Spring Boot如何使用Mybatis XML 配置版【附详细步骤】
前面介绍了Spring Boot 中的整合Thymeleaf前端html框架,同时也介绍了Thymeleaf 的用法.不清楚的朋友可以看看之前的文章:https://www.cnblogs.com/z ...
- Ktor: Kotlin Web后端框架 快速开始入门
Ktor: Kotlin Web后端框架 Web backend framework for Kotlin 快速开始入门 Ktor 简介 Ktor 是一个用于在 Kotlin 中快速创建 web 应用 ...
- Mybatis莫名报错或Mapper.xml配置后爆红或显示The error may exist in com/jdsydwr/dao/UserMapper.java找不到Mapper接口的修改方法
报错内容 org.apache.ibatis.exceptions.PersistenceException: ### Error building SqlSession. ### The erro ...
- 银行管理系统(使用SQL Server)-Python快速编程入门(第2版)-人民邮电出版社-阶段案例
阶段案例-银行管理系统 题目描述 银行管理系统是一个集开户.查询.取款.存款.转账.锁定.解锁.退出等一系列业务于一体的管理系统,随着计算机技术在金融行业的广泛应用,银行企业采用管理系统替代了传统手工 ...
- Python快速编程入门 第2版 实训案例及课后编程题
目录 本文档仅供参考,更新了 第2章 第3章 第4章 第5章 第6章 第7章 本文档仅供参考,更新了6.7章 第2章 2.4.1打印购物小票 蚂蚁森林是支付宝客户端发起"碳账户"的 ...
- 【python快速编程入门 第2版】第一章 python概述 习题
一.填空题 1.Python是面向___对象的高级语言. 2.Python 可以在多种平台运行,这体现了Python语言_可移植性的特性. 3.Python模块的本质是.py文件. 4.使用impor ...
- spring整合mybatis的xml配置
之前在SSM之Mybatis概览_数字公民某杨的博客-CSDN博客有这个示意图: mybatis框架有两类xml配置,一个是全局的xml,另一类是单个接口的xml. 当spring整合mybatis, ...
- java day53【 Mybatis框架概述 、 Mybatis 框架快速入门、自定义 Mybatis 框架 】
第1章 框架概述 1.1 什么是框架 1.1.1 什么是框架 框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种 定义认为,框架是可被应用开发者定 ...
最新文章
- 爬虫训练之--获取错误并将其保存进本地文件
- 分隔单词和标点符号示例
- SAP实施方法论之探讨-现状调研与需求分析
- 【GNN】2022年最新3篇GNN领域综述!
- EfficientNet论文阅读笔记
- allegro下快捷键设置[转贴]
- 点击率预估与冷启动(二)
- 开博啦——半路出家做运维以来的一些杂感
- 【渝粤教育】国家开放大学2018年春季 8636-22T实用心理学 参考试题
- 计算机的分类按cpu芯片可以分为,按CPU芯片可分为单片机、单板机、多芯片机和多板机...
- 解决办法:nvidia-settings:ERROR: Unable to load info from any available system
- 联想笔记本电脑安装完Ubuntu16.04出现搜索不到wifi的问题
- java工程师的职业规划_Java工程师如何进行职业规划?
- pathinfo 伪静态 详细解析PATH_INFO 和 ORIG_PATH_INFO技术分享
- win10驱动开发16——派遣函数(直接方式读操作)
- C语言蜗牛爬墙(个人练习)
- keil中出现警告:last line of file ends without a newline解决方法
- RAFT共识算法学习
- django中models的filter过滤方法
- EC11旋转编码器电路和程序
热门文章
- javascript 闭包和原型
- python代码怎么练_自己练习的Python代码(1)
- 拓端tecdat|关联规则APRIORI挖掘豆瓣读书评论爬虫采集数据与可视化
- 拓端tecdat|用于NLP的Python:使用Keras进行深度学习文本生成
- java未完成的标记,eclipse中的任务标记(TODO、FIXME、XXX)
- (5)Matplotlib_grid
- python导入上级目录的模块
- SQL语言概况(4.1)
- 为什么深度学习有效?(why deep learning works)
- cloudquery.php态势感知,CloudQuery v1.3.4 版本更新