SSM框架之mybaitis框架详解
三层架构
1、什么是三层架构?
- 在项目开发中,遵循的一种形式模式,分为三层
- 界面层:用啦接受客户端的输入,调用业务逻辑层进行功能处理,返回结果给客户端,过去的servlet就是界面层的功能
- 业务逻辑层:用来进行整个项目的业务逻辑处理,向上为界面层提供处理结果,向下问数据访问层要数据
- 数据访问层:专门用来进行数据库的增删查改操作,向上为业务逻辑层提供数据
- 各层之间的调用顺序是固定的,不允许跨层访问
- 界面层<—->业务逻辑层<—–>数据访问层
SSM框架
常用的况框架SSM
Spring:它是整合其他框架的框架,它的核心是IOC和AOP,它由20多个模块构成的,在很多领域都提供了很好的解决方案,是一个很强大的存在
SpriingMVC:他是Spring家族的医院,专门用来优化控制器(Servlet)的,提供了极其简单数据提交,数据携带,页面跳转等功能
MyBatis:是持久化层的一个框架,用来进行数据库的访问哟话,专注于SQL语句,极大的简化了JDBC的访问
什么是框架?
- 它是一个半成品软件,将所有的公共的,重复的功能解决掉,帮助程序员快速高效的进行开发,他是可复用的,可扩展的
什么是MyBatis框架
是Apache的一个开源项目iBatis
MyBaits最主要用来完成数据访问层的优化,它专注于sql语句,简化了过去JDBC繁琐的访问机制
添加框架的步骤
- 添加依赖
- 添加配置
- 创建ssm数据库,添加student表,并且插入数据
create database ssm default charset utf8;
use ssm;
create table student(
id int(11) AUTO_INCREMENT primary key,
name varchar(255) default null,
email varchar(255) default null,
age int(11) default null
) ENGINE=InnoDB default charset=utf8;
insert into student(name,email,age) values("张三",'zhangsan@126.com',22);
insert into student(name,email,age) values("李四",'lisi@126.com',21);
insert into student(name,email,age) values("王五",'wangwu@126.com',22);
insert into student(name,email,age) values("赵六",'zhaoliu@126.com',24);
select * from student;
配置SqlMapConfig.xml文件
<?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><!--读取属性文件,jdbc.properties属性:resource:从resource目录下找执行名称的文件加载url:使用绝对路径加载属性文件--><properties resource="jdbc.properties"></properties><!--配置数据库环境变量(数据库连接配置)--><!--environments里面可以配置多套environmentdefault:使用下面的environment标签的id属性进行执行配置--><environments default="development"><!--id:就是提供给environment的default属性是有--><environment id="development"><!--配置事务管理器type属性:指定事务管理的方式 JDBC:事务的控制交托给程序员处理MANAGED:由容器(Spring)来管理事务--><transactionManager type="JDBC"></transactionManager><!--配置数据源type:指定不同的配置方式JNDI:Java命名目录接口,在服务器端进行数据库连接池的管理POOLED:使用数据库连接池进行数据库的连接配置UNPOLLED:不使用数据库连接池--><dataSource type="POOLED"><!--配置数据库连接的基本参数--><property name="driver" value="${jdbc.driverClassName}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><!--注册mapper.xml文件resource:从resource目录下找指定名称文件注册url:使用绝对路径找文件注册class:动态代理方式下的注册--><mappers><mapper resource="StudentMapper.xml"></mapper></mappers></configuration>
配置StudentMapper.xml文件
<?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:是整个文件的大标签,用来开始和结束xml
属性:namespace:指定命名空间(相当于包名),用来区分不同mapper.xml文件中相同的id属性
-->
<mapper namespace="su"><!--完成查询全部学生的功能resultType:指定查询返回结果集的类型,如果是集合,则必须是泛型的类型parameterType:如果有参数,则通过它来指定参数类型--><select id="getAll" resultType="com.bjpowernode.pojo.Student">select id,name,email,agefrom student</select>
</mapper>
测试
//使用文件流的读取核心配置文件SqlMapConfigInputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");//创建SqlSessionFactory工厂SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);//取出SqlSession的对象SqlSession sqlSession = factory.openSession();//完成查询操作List<Student> list = sqlSession.selectList("su.getAll");list.forEach(student -> System.out.println(student));//关闭SqlSessionsqlSession.close();
使用mybatis进行增删查改
SqlMapConfig配置文件
<!--按主键id查询学生信息--><select id="getById" parameterType="int" resultType="com.bjpowernode.pojo.Student">select id,name,email,age from student where id=#{id}</select><!--按学生名称模糊查询--><select id="getByName" parameterType="string" resultType="com.bjpowernode.pojo.Student">select id,name,email,age from student where name like '%${name}%'</select><!--增加学生--><insert id="insert" parameterType="com.bjpowernode.pojo.Student">insert into student(name,email,age) values (#{name},#{email},#{age})</insert><!--按主键删除学生--><delete id="delete" parameterType="int">delete from student where id = #{id}</delete><!--修改学生--><update id="update" parameterType="com.bjpowernode.pojo.Student">update student set name=#{name},email=#{email},age=#{age} where id = #{id}</update>
测试程序
//读取核心配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//取出SqlSession
SqlSession sqlSession = factory.openSession();//完成查询操作List<Student> list = sqlSession.selectList("su.getAll");list.forEach(student -> System.out.println(student));/*for (Student x : list){System.out.println(x);}*///关闭SqlSessionsqlSession.close();//按主键查询学生Student stu = sqlSession.selectOne("su.getById",1);System.out.println(stu);//关闭SqlSessionsqlSession.close();
//执行模糊查询List<Student> list = sqlSession.selectList("su.getByName","李");for (Student x : list){System.out.println(x);}//list.forEach(student -> System.out.println(student));//关闭SqlSessionsqlSession.close();
//增加学生int num = sqlSession.insert("su.insert", new Student("苏叶", "210469@qq.com", 21));sqlSession.commit();sqlSession.close();
//删除学生int delete = sqlSession.delete("su.delete", 5);sqlSession.commit();sqlSession.close();
//修改学生int update = sqlSession.update("su.update", new Student(2, "王麻子", "wm@126.com", 18));sqlSession.commit();sqlSession.close();
注意:执行增删改语句一定要提交事务
Mybatis对象分析
1、Resources类
- 就是解析SqlMapConfig.xml文件,创建出相应的对象
- InputStream in = Resources.getResourceAsStream(“SqlMapConfig.xml”);
2、SqlSessionFactoryBuilder接口
- 使用ctrl+h查看本接口的子接口及实现类
- DefaultSqlSessionFactory是实现类
- SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
3、SqlSession接口
- DefaultSqlSession实现类
- SqlSession sqlSession = factory.openSession();
为实体类注册别名
1、单个注册
在SqlMapConfig.xml文件中properties 标签后 environments 前面加入标签,注册之后就可以在Mapper.xml文件中的resultType属性或者parameterType属性中使用这个别名
<!--注册实体类的别名--><typeAliases><!--单个注册--><typeAlias type="com.bjpowernode.pojo.Student" alias="student"></typeAlias></typeAliases>
2、批量注册
<!--批量注册别名别名是类名的驼峰命名规范--><package name="com.bjpowernode.pojo"/>
批量把这个目录下的所有实体类都注册别名,别名是类名的驼峰命名规范
输出日志:固定的写法
<!--设置日志输出底层执行的代码--><settings><setting name="logImpl" value="STDOUT_LOGGING"/></settings>
动态代理
1、动态代理存在的意义
- 在三层架构中,业务逻辑层需要通过接口访问数据访问层的功能,可以使用动态代理
2、动态代理的实现规范
- UserMapper.xml文件与UserMapper.java的接口必须在同一个目录。
- UserMapper.xml文件与UserMapper.java接口的文件名必须一致,后缀可以不管
- UserMapper.xml文件中的标签id的值与UserMapper.java的接口中方法名称完全一致
- UserMapper.xml文件中的标签的parameterType属性值与UserMapper.java的接口中方法参数类型完全一致
- UserMapper.xml文件中标签的resultType值与UserMapper.java的接口方法的返回值类型必须一致
- UserMapper.xml文件中标签的namespace属性必须是接口的完全限定名称,例如com.bjpowernode.mapper.UserMapper
- 在SqlMapConfig.xml文件中注册mapper文件时,使用class=接口的完全限定名称,例如com.bjpowernode.mapper.UserMapper
3、动态代理的访问
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);sqlSession = factory.openSession();uMapper = sqlSession.getMapper(UsersMapper.class);//直接调用方法List<Users> list = uMapper.getAll();for(Users x : list){System.out.println(x);}}
//
//原来的方式public void testGetAll() throws IOException {//完成查询操作//只能通过namespace标注下id的值来调用方法,而且不同的语句使用不同的sqlsession方法List<Student> list = sqlSession.selectList("su.getAll");list.forEach(student -> System.out.println(student));}
使用动态代理的方式进行获取数据
#{}和${}的区别
#{}占位符
传参的时候大部分使用#{}传参,它的底层使用的是PreparedStatement对象,是安全的数据库访问,防止sql注入
#{}里面写什么东西,主要看parameterType参数的类型
- 如果parameterType的类型是简单类型(8种基本(封装)+String),则#{}里面随便写
<select id="getById" resultType="users" parameterType="int"> >入参类型是简单类型select id,username,birthday,sex,address from users where id = #{id} >这个里面可以随便写</select>
- parameterType的类型如果是实体类型,则#{}里面只能是类中的成员变量的名称,并且区分大小写
<insert id="add" parameterType="users">insert into users(username,birthday,sex,address) values(#{userName},#{birthday},#{sex},#{address})</insert>
${}字符串拼接或字符串替换
字符串拼接,一般用于模糊查询中,建议少用,因为有sql注入的风险
也分为两种情况,同样看parameterType类型
- 如果parameterType类型是简单类型,则${}里面随便写,但是分版本,如果是3.5.1及以下版本,只能写value
<select id="getByLike" parameterType="string" resultType="users"> >传参是简单类型select id,username,birthday,sex,address from users where username like '%${userName}%' >${}里面可以随便写</select>
- parameterType的类型如果是实体类型,则${}里面只能是类中的成员变量的名称(溴铵在已经很少用了)
优化模糊查询,因为直接使用${}这个进行拼接会有sql注入危险,所以以后我们使用concat()函数来进行模糊查询
<select id="getByNameGood" parameterType="string" resultType="users">select id,username,birthday,sex,address from users where username like concat('%',#{name},'%')</select>
字符串替换使用${}
在有的时候我们需要进行模糊查询的时候,不仅仅是根据用户名,有的时候根据地址进行模糊查询,这个时候我们肯定是不能写两个不同的sql语句,这样太麻烦了,所以这个时候我们就要需要用到注解
List<Users> getByNameOrAddress(@Param("columnName") String columnName,@Param("columnValue") String columnValue);
<!----> <!--如果参数超过一个则parameterType不用写--><select id="getByNameOrAddress" resultType="users">select id,username,birthday,sex,address from users where${columnName} like concat('%',#{columnValue},'%')</select>
然后进行测试,要查询哪个字段,就靠自己传参
@Testpublic void testGetByNameGoodOrAddress(){List<Users> list = uMapper.getByNameOrAddress("address","南");for (Users x:list){System.out.println(x);}}
返回主键业务
假如在有的时候,我们插入一行数据,但是主键是自增的,并且关联了其他表,且也要为其增加数据,这样我们还要先查询自增的主键是多少再进行增加另一个表的数据,这样很麻烦,所以我们可以在插入数据的时候返回主键
<insert id="add" parameterType="users"><selectKey keyProperty="id" resultType="int" order="AFTER">select last_insert_id()</selectKey>insert into users(username,birthday,sex,address) values(#{userName},#{birthday},#{sex},#{address})</insert>
- selectKey标签的详解:
- keyProperty:users对象的哪个属性来返回主键值
- resultType:返回主键的类型
- order:在插入语句前还是后返回主键的值
动态SQL
什么是动态sql
- 可以定义代码片段,可以进行逻辑判断,可以进行循环处理(批量处理),使条件判断更简单
:用来定义代码片段,可以将所有的列名,或者复杂的条件定义为代码片段,供使用时调用
:用来引用标签定义的代码片段
<!--定义代码片段--><sql id="allColumns">id,username,birthday,sex,address</sql><!--在sql语句中引用--><select id="getAll" resultType="users">select <include refid="allColumns"></include> from users</select>
进行条件判断
进行多条件拼接,在查询,删除,更新中使用
- 强化select查询,使用if进行判断
<select id="getByCondition" parameterType="users" resultType="users">select <include refid="allColumns"></include> from users<where><if test="userName != null and userName !=''">and username like concat('%',#{userName},'%')</if><if test="birthday != null">and birthday = #{birthday}</if><if test="sex != null and sex != ''">and sex = #{sex}</if><if test="address != null and address != ''">and address like concat('%',#{address},'%')</if></where></select>
测试
@Testpublic void testGetByCondition(){Users users = new Users();users.setUserName("小");List<Users> list = uMapper.getByCondition(users);for (Users x : list){System.out.println(x);}}
- :有选择的进行更新处理,至少更新一列
<update id="updateBySet" parameterType="users" >update users<set><if test="userName != null and userName != ''">username = #{userName},</if><if test="birthday != null">birthday = #{birthday},</if><if test="sex != null and sex != ''">sex = #{sex},</if><if test="address != null and address != ''">address = #{address},</if></set>where id = #{id}</update>
测试
@Testpublic void testUpdateBySet(){Users users = new Users();users.setId(6);users.setUserName("TheShy");int i = uMapper.updateBySet(users);sqlSession.commit();}
:用来进行循环遍历,完成循环条件查询,批量删除,批量增减,批量更新
collection:用来指定入参的类型,如果是List集合则为小写的list,Map为map,数组Array是array
item:每次循环遍历出来的值或者对象
separator:多个值或者多个对象之间的分隔符
open:整个循环前的前括号
close:整个循环的后括号
<select id="getByIds" resultType="users">select <include refid="allColumns"></include>from userswhere id in (<foreach collection="array" item="id" separator="," open="(" close=")">#{id}</foreach>)</select>
使用foreach实现批量删除
<delete id="deleteBatch">delete from userswhere id in<foreach collection="array" item="id" separator="," open="(" close=")">#{id}</foreach></delete>
测试
@Testpublic void testDeleteBatch(){Integer[] array = {4,7};int i = uMapper.deleteBatch(array);sqlSession.commit();}
注意:如果要使用批量更新,需要再properties配置文件中的url后加上 &allowMultiQueries=true
指定参数位置
如果入参是多个,可以通过指定参数位置进行传参,是实体类包含不住的条件,实体类只能封装住成员变量的条件,如果某个成员变量需要有区间范围之内的判断,或者两个值进行处理,则实体类包不住
- 例如:查询指定日期范围内的用户信息
- 首先定义接口中的方法,因为是在一个区间之内,所以需要两个参数的方法
List<Users> getByBirthday(Date beigin,Date end);
- 然后在Mapper.xml文件中编写sql语句
<select id="getByBirthday" resultType="users">select <include refid="allColumns"></include>from userswhere birthday between #{arg0} and #{arg1}</select>
在进行多个参数查询的时候,我们可以用 arg0 开始指定,从零开始,依次递增
- 测试
@Testpublic void testGetByBirthday() throws ParseException {Date begin = sf.parse("2001-01-1");Date end = sf.parse("2003-01-1");List<Users> byBirthday = uMapper.getByBirthday(begin, end);for (Users x : byBirthday){System.out.println(x);}}
入参为Map
- 如果入参超过一个以上,使用map封装查询条件,更有语义,查询条件更明确
List<Users> getByMap(Map map);
<!--#{birthdayBegin} 为map集合的key#{birthdayEnd} 为map集合的value--><select id="getByMap" resultType="users">select <include refid="allColumns"></include>from userswhere birthday between #{birthdayBegin} and #{birthdayEnd}</select>
@Testpublic void testGetByMap() throws ParseException {Date begin = sf.parse("2001-01-1");Date end = sf.parse("2003-01-1");Map map = new HashMap<>();map.put("birthdayBegin",begin);map.put("birthdayEnd",end);List<Users> byBirthday = uMapper.getByMap(map);for (Users x : byBirthday){System.out.println(x);}}
返回值是map
- 如果返回的数据实体类无法包含,可以使用map返回多张表中若干的数据,然后后这些数据之间没有任何关系,就是Object类型,map的key就是列名或者别名
//返回值是map(一行)Map getReturnMap(Integer id);//返回值为多行mapList<Map> getAllMap();
<!--返回值为一行map--><select id="getReturnMap" parameterType="int" resultType="map">select username,address from userswhere id = #{id}</select><!--返回值为多行map--><select id="getAllMap" resultType="map">select username,address from users</select>
//返回值为一行map@Testpublic void testGetReturnMap(){Map returnMap = uMapper.getReturnMap(2);System.out.println(returnMap.get("username"));System.out.println(returnMap.get("address"));}//返回多行Map@Testpublic void testGetAllMap(){List<Map> allMap = uMapper.getAllMap();for (Map x : allMap){System.out.println(x);}}
resultMap的用法
- 在有的时候实体类的属性和数据库表的字段不一样的情况下,可以使用resultMap进行关系映射
<!--实体类和表中的字段不一样的情况下,可以使用resultMap手工完成映射--><resultMap id="bookmap" type="book"><!--id是你在sql语句中设置的id type是你映射的类型--><!--主键绑定--><!--property为你实体类中的属性,column为你数据库中对应的字段名--><id property="id" column="bookid"></id><!--非主键绑定--><result property="name" column="bookname"></result></resultMap><select id="getAllBook" resultMap="bookmap"> <!--设置返回值为resultMap,并且设置名字,为你resultMap中的id-->select bookid,bookname from book</select>
表的关联关系
关联关系是有方向的
一对多关联:一个老师可以教多个学生,多个学生只有一个老师来教,站在老师方向,就是一对多关联
多对一关联:一个老师可以教多个学生,多个学生只有一个老师来教,站在学生的方向,这就是多对一的关系
一对一关联:一个老师辅导一个学生,一个学生只请教一个老师,学生和老师一对一
多对多关联:园区划线的车位和园区的任意一辆车,一个车位可以停任意一辆车,任意一辆车可以停在任意的一个车位。
一对多的关联管理
- 客户和订单就是典型的一对多关联关系,一个客户名下可以有多个订单,客户表是一方,订单表是多方
使用一对多的关联关系,可以按组查询客户的同时查询该客名下所有的订单
- 把两个表创建实体类,客户表可以创建一个订单类型的属性
//客户表private Integer id;private String name;private Integer age;private List<Orders> ordersList;
//订单orders表private Integer id;private String orderNumber;private Double orderPrice;
因为返回的数据不仅仅有客户表中的信息,还有订单表中的信息,所以数据库要多表连接查询,查询的数据的不同,所以要使用resultMap进行一个绑定
<resultMap id="customermap" type="customer"><id property="id" column="cid"></id><result property="name" column="name"></result><result property="age" column="age"></result><!--orders属性绑定--><collection property="ordersList" ofType="orders"><id property="id" column="oid"></id><result property="orderNumber" column="orderNumber"></result><result property="orderPrice" column="orderPrice"></result></collection></resultMap><select id="getById" parameterType="int" resultMap="customermap">select c.id cid,name,age,o.id oid,orderNumber,orderPrice,customer_idfrom customer c left join orders o on c.id = o.customer_idwhere c.id = #{id}</select>
多对一关联关系:订单和客户就是多对一关联,站在订单的方向查询同时将客户信息查询出来这就是多对一查询,同理可以在订单的实体类中设置用户customer为属性,然后创建订单的接口和其Mapper.xml文件
总结:无论什么关联关系,如果某一方持有另一方的集合,则使用标签完成映射,如果某方持有另一方对象,则使用标签完成映射
事务
多个操作同时完成,或者同时失败成为事务处理
- 事务有四个特性:一致性,持久性,原子性,隔离性
- 在mybatis中是设置事务,设置为程序员自己处理的提交和回滚
<transactionManager type="JDBC"></transactionManager>
- 也就可以设置为自动提交
sqlSession = factory.openSession(); //默认是手工提交事务,设置为false也是手动提交事务,设置为true为自动提交事务
sqlSession = factory.openSession(true);//设置为自动提交,在增删改后面不需要commit()
缓存
- mybatis框架提供了两级缓存,一级缓存和二级缓存,默认开启一级缓存
- 缓存就是为了提高查询效率,如果数据库中发生改变,那么将会清空缓存
- 使用缓存后查询的流程:
- 查询时先到缓存里面查,如果没有则去数据库查询,放在缓存一份,然后返回给客户端,下次再查询的时候,不再访问数据库,直接在缓存里面拿。如果数据库发生了commit()操作,那么将会清空缓存。
- 一级缓存,使用的是sqlSession的作用域,同一个sqlSession共享一级缓存的数据
- 二级缓存使用的是mapper的作用域,不同的sqlSession只要访问的是同一个mapper.xml文件,则共享二级缓存作用域
ORM
- ORM(Object Relational Mapping):对象映射关系
- mybatis框架是ORM非常优秀的框架
- Java语言中以对象的方式操作数据,存到数据库中是以表的方式进行存储,对象中的成员变量与表中的列之间的数据互换成为映射,整个这套操作就是ORM
- 持久化的操作:将对象保存到关系型数据库中,将关系型数据库中的数据读出来以对象的形式封装
- mybatis是持久化层优秀的框架
SSM框架之mybaitis框架详解相关推荐
- java集合框架史上最详解(list set 以及map)
title: Java集合框架史上最详解(list set 以及map) tags: 集合框架 list set map 文章目录 一.集合框架总体架构 1.1 集合框架在被设计时需满足的目标 1.2 ...
- 超轻量级DI容器框架Google Guice与Spring框架的区别教程详解及其demo代码片段分享...
超轻量级DI容器框架Google Guice与Spring框架的区别教程详解及其demo代码片段分享 DI框架 Google-Guice入门介绍 转载于:https://www.cnblogs.com ...
- 自动化测试框架[Cypress元素操作详解]
前提 已经熟练掌握了Cypress的基本知识,请参考自动化测试框架[Cypress概述]和自动化测试框架[各自动化测试框架比较] 已经熟练掌握Cypress环境配置,请参考自动化测试框架[Cypres ...
- androidentity什么用_Android ORM 框架:GreenDao 使用详解(进阶篇)
前言 在 Android ORM 框架:GreenDao 使用详解(基础篇) 中,我们了解了 GreenDao 的基本使用,本文我们将深入讲解 GreenDao 的使用 . 一.复杂表结构 a, 使用 ...
- java 线程同步的list_java集合框架线程同步代码详解
List接口的大小可变数组的实现.实现了所有可选列表操作,并允许包括null在内的所有元素.除了实现List接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小.(此类大致上等同于Vector ...
- SpringSecurity权限管理框架系列(六)-Spring Security框架自定义配置类详解(二)之authorizeRequests配置详解
1.预置演示环境 这个演示环境继续沿用 SpringSecurit权限管理框架系列(五)-Spring Security框架自定义配置类详解(一)之formLogin配置详解的环境. 2.自定义配置类 ...
- Android Binder框架实现之Parcel详解之基本数据的读写
Android Binder框架实现之Parcel详解之基本数据的读写 Android Binder框架实现目录: Android Binder框架实现之Binder的设计思想 Android ...
- Android Binder框架实现之bindService详解
Android Binder框架实现之bindService详解 Android Binder框架实现目录: Android Binder框架实现之Binder的设计思想 Android Bi ...
- spring cloud tencent:框架概括及组件详解(一)
0.引言 近期腾讯开源了自己的spring cloud体系技术,称职的技术从业者除做好自己的本职工作外,还需要紧跟技术潮流,实时了解前沿技术,所以本期我们就来一起学习spring cloud tenc ...
最新文章
- php字符串处理函数大全
- python urllib3离线安装_全球Python库下载前10名
- android配置开发环境ubuntu
- Java继承概述以及Java继承案例和继承的好处
- 红队技巧-域渗透的协议利用
- java excel 电话号码_数值或者电话号码被EXCEL转成了科学计数法,用XSSFCell 如何读取...
- L3-020 至多删三个字符 (30 分)-PAT 团体程序设计天梯赛 GPLT
- 【免费毕设】成绩查询系统(系统+论文+答辩PPT)
- 《流畅的Python》读书笔记——Python序列的修改、散列和切片
- Windows 10 超过Windows 7成为最受欢迎的操作系统
- python小波包分解_小波包变换(Wavelet Packet Transform)的学习笔记
- 软件工程专业如何论文选题?
- 线性回归相关系数c语言,线性回归中的相关系数;
- 如何有效的获得高质量的大规模标注数据?
- html自动增加文本框,html创建文本框
- 【矩阵论笔记】相似对角化、特征子空间(几何重数和代数重数)
- STM32——C语言基础
- vue的微信语音功能,录音+对接口返回amr音频播放
- python生成字符画_Python生成字符画 | 文艺数学君
- ubuntu16启用daytime服务