MyBatisPlus 入门教程,这篇很赞
在之前的文章中我们经常使用MybatisPlus进行增删改查,可能有些小伙伴对mybatisplus不是很熟悉,今天特意出了一般入门级的教程,我自己也是一边学习一边写的,有什么地方写的不好的地方请留意指出。
快速入门的小例子
准备数据库和测试数据
#创建用户表
CREATE TABLE user (
id BIGINT(20) PRIMARY KEY NOT NULL COMMENT '主键',
name VARCHAR(30) DEFAULT NULL COMMENT '姓名',
age INT(11) DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
manager_id BIGINT(20) DEFAULT NULL COMMENT '直属上级id',
create_time DATETIME DEFAULT NULL COMMENT '创建时间',
CONSTRAINT manager_fk FOREIGN KEY (manager_id)
REFERENCES user (id)
) ENGINE=INNODB CHARSET=UTF8;
#初始化数据:
INSERT INTO user (id, name, age, email, manager_id, create_time)
VALUES (1087982257332887553, '大boss', 40, 'boss@baomidou.com', NULL, '2019-01-11 14:20:20'),
(1088248166370832385, '王天风', 25, 'wtf@baomidou.com', 1087982257332887553, '2019-02-05 11:12:22'),
(1088250446457389058, '李艺伟', 28, 'lyw@baomidou.com', 1088248166370832385, '2019-02-14 08:31:16'),
(1094590409767661570, '张雨琪', 31, 'zjq@baomidou.com', 1088248166370832385, '2019-01-14 09:15:15'),
(1094592041087729666, '刘红雨', 32, 'lhm@baomidou.com', 1088248166370832385, '2019-01-14 09:48:16');
配置数据库信息
在项目的resources
目录下新建application.yml
文件,内容如下:
spring:
datasource:
url: jdbc:mysql://localhost:3306/springboot?serverTimezone=GMT%2B8
username: root
password: nomore532
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
logging:
level:
root: warn
com.demo01.Mapper: trace
pattern:
console: "%p%m%n"
新建实体类型
在项目根目录下新建一个包,名字为Entity,然后,新建一个名字为User.java
的实体类型。
package com.demo01.Entity;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class User {
//主键
private Long id;
//用户名
private String name;
//邮箱
private String email;
//年龄
private Integer age;
//直属上级
private Long managerId;
//创建时间
private LocalDateTime createTime;
}
注意:@Data注解能在编译是自动生成get和set方法。
新建Mapper包,并创建UserMapper接口类。
在项目的根目录下新建一个名为Mapper
包,并创建UserMapper.java接口
类,继承MyBatis-Plus
的BaseMapper
基类。
package com.demo01.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.demo01.Entity.User;
public interface UserMapper extends BaseMapper<User> {
}
注意:MyBatisPlus的BaseMapper基类需要存入一个泛型,这个泛型是要操作的实体类型。
并在启动类型添加扫描路径
@SpringBootApplication
@MapperScan("com.demo01.Mapper")
public class Demo01Application {
public static void main(String[] args) {
SpringApplication.run(Demo01Application.class, args);
}
}
新建测试方法
查询所有的用户信息
package com.demo01;
import com.demo01.Entity.User;
import com.demo01.Mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest(classes = Demo01Application.class)
class Demo01ApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void select() {
List<User> list = userMapper.selectList(null);
list.forEach(System.out::println);
}
}
运行结果如下:
通用Mapper
新增(Create)方法
在测试目录下新建一个测试类,名字为InserTest.java
,内容如下:
package com.demo01;
import com.demo01.Entity.User;
import com.demo01.Mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest(classes = Demo01Application.class)
class InsertTests {
@Autowired
private UserMapper userMapper;
@Test
public void insert(){
User user = new User();
user.setName("刘强东");
user.setAge(37);
user.setEmail("lqd@jd.com");
user.setManagerId(1087982257332887553L);
int rows = userMapper.insert(user);
System.out.println("影响行数"+rows);
}
}
注意:insert方法需要的参数是一个实体,返回参数是影响行数
运行结果如下:
查数据库结构如下:
常用注解
@TableName
描述:表名注解
属性 | 类型 | 必须指定 | 默认值 | 描述 |
---|---|---|---|---|
value | String | 否 | "" | 表名 |
schema | String | 否 | "" | schema |
keepGlobalPrefix | boolean | 否 | false | 是否保持使用全局的 tablePrefix 的值(如果设置了全局 tablePrefix 且自行设置了 value 的值) |
resultMap | String | 否 | "" | xml 中 resultMap 的 id |
autoResultMap | boolean | 否 | false | 是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建并注入) |
excludeProperty | String[] | 否 | {} | 需要排除的属性名(@since 3.3.1) |
@TableId
描述:主键注解
属性 | 类型 | 必须指定 | 默认值 | 描述 |
---|---|---|---|---|
value | String | 否 | "" | 主键字段名 |
type | Enum | 否 | IdType.NONE | 主键类型 |
type的类型包括以下几种:
- AUTO:数据库ID自增。
- NONE:无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
- INPUT:insert前自行set主键值
- ASSIGN_ID:分配ID(主键类型为Number(Long和Integer)或String)(since 3.3.0),使用接口
IdentifierGenerator
的方法nextId
(默认实现类为DefaultIdentifierGenerator
雪花算法) - ASSIGN_UUID :分配UUID,主键类型为String(since 3.3.0),使用接口
IdentifierGenerator
的方法nextUUID
(默认default方法)
TableField
描述:字段注解(非主键)
详细的注解请查看MybatisPlus的官网
排查非表字段的三种方式
- transient:不参与序列化
- static
- TableField(exist=false)
MybatisPlus查询方法(Retrieve)
普遍查询方法
selectById
@Test
public void selectByIdTest(){
User user = userMapper.selectById(1435065643693645826L);
System.out.println(user);
}
运行结果:
selectBatchIds
@Test
public void selectByIds(){
List<Long> idsList = Arrays.asList(
1088248166370832385L,
1094590409767661570L,
1435065643693645826L
);
List<User> users = userMapper.selectBatchIds(idsList);
users.forEach(System.out::println);
}
运行结果:
selectByMap
@Test
public void selectByMapTest(){
//map.put("name","王天风")
//map.put("age",25)
//where name="王天风" and age=25
Map<String,Object> columnMap = new HashMap<>();
columnMap.put("name","王天风");
columnMap.put("age",25);
List<User> users = userMapper.selectByMap(columnMap);
users.forEach(System.out::println);
}
注意:columnMap中的键是数据库中的字段,不是实体类型的属性。
运行结果:
以条件构造器为参数的查询方法
selectList
/**
* 1、名字中包含雨并且年龄小于40
* name like '%雨%' and age<40
*/
@Test
public void selectByWrapper(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("name","雨").lt("age",40);
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
运行结果
/**
* 2、名字中包含雨年并且龄大于等于20且小于等于40并且email不为空
* name like '%雨%' and age between 20 and 40 and email is not null
*/
@Test
public void selectByWrapper2(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("name","雨").between("age",20,40).isNotNull("email");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
运行结果:
/***
* 3、名字为王姓或者年龄大于等于25,按照年龄降序排列,年龄相同按照id升序排列
* name like '王%' or age>=25 order by age desc,id asc
*/
@Test
public void selectByWrapper3(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.likeRight("name","王").or().ge("age",25).orderByDesc("age").orderByAsc("id");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
/**
* 4、创建日期为2019年2月14日并且直属上级为名字为王姓
* date_format(create_time,'%Y-%m-%d')='2019-02-14'
* and manager_id in (select id from user where name like '王%')
*/
@Test
public void selectByWrapper4(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.apply("date_format(create_time,'%Y-%m-%d') = {0}","2019-02-14")
.inSql("manager_id","select id from user where name like '王%'");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
运行结果:
/**
* 5、名字为王姓并且(年龄小于40或邮箱不为空)
* name like '王%' and (age<40 or email is not null)
*/
@Test
public void selectByWrapper5(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.likeRight("name","王").and(wq->wq.lt("age",40).or().isNotNull("email"));
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
运行结果:
/**
* 6、名字为王姓或者(年龄小于40并且年龄大于20并且邮箱不为空)
* name like '王%' or (age<40 and age>20 and email is not null)
*/
@Test
public void selectByWrapper6(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.likeRight("name","王").or(wq->wq.lt("age",40).gt("age",20).isNotNull("email"));
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
运行结果:
/**
* 7、(年龄小于40或邮箱不为空)并且名字为王姓
* (age<40 or email is not null) and name like '王%'
*/
@Test
public void selectByWrapper7(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//queryWrapper.and(wq->wq.lt("age",40).or().isNotNull("email")).and(wq->wq.likeRight("name","王"));
queryWrapper.nested(wq->wq.lt("age",40).or().isNotNull("email"))
.likeRight("name","王");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
};
运行结果:
/**
* 8、年龄为30、31、34、35
* age in (30、31、34、35)
*/
@Test
public void selectByWrapper8(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.in("age",Arrays.asList(30,31,34,35));
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
运行结果:
/**
* 9、只返回满足条件的其中一条语句即可
* limit 1
*/
@Test
public void selectByWrapper9(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.likeRight("name","王").or(wq->wq.lt("age",40).gt("age",20).isNotNull("email")).last("limit 1");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
运行结果:
select中字段不全出现的处理方法
/**
* 10、名字中包含雨并且年龄小于40(需求1加强版)
* 第一种情况:select id,name
* from user
* where name like '%雨%' and age<40
* 第二种情况:select id,name,age,email
* from user
* where name like '%雨%' and age<40
*/
@Test
public void selectByWrapper10(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("id","name").like("name","雨").lt("age",40);
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
@Test
public void selectByWrapper11(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("name","雨").lt("age",40)
.select(User.class,info-> !info.getColumn().equals("create_time") && !info.getColumn().equals("manager_id")) ;
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
运行结果:
条件构造器中condition作用
condition作用是构造的条件中如何为true就加入,为false就不加入条件。
从AbstractWrapper<T, String, QueryWrapper<T>>
的源码可以看到很多方法都有condition
参数,它是一个布尔型的参数,意思就是是否将该sql
语句(像in()
、like()
)加在总sql
语句上,如下图所示。
@Test
public void testCondition() {
String name="王";
String email="";
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like(!StringUtils.isEmpty(name),"name",name)
.like(!StringUtils.isEmpty(email),"email",email);
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
运行结果:
创建条件构造器是传入实体对象
@Test
public void selectByWrapperEntity(){
User whereuser = new User();
whereuser.setName("刘红雨");
whereuser.setAge(32);
QueryWrapper<User> queryWrapper = new QueryWrapper<>(whereuser);
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
默认情况下条件是等值,如下图,如果需要设置为like
,需要在实体属性添加注解。
...省略...
@TableField(condition = SqlCondition.LIKE)
private String name;
...省略...
condition参数可以自定义。
运行结果:
条件构造器中allEq用法
allEq(Map<R, V> params)
allEq(Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, Map<R, V> params, boolean null2IsNull)
个别参数说明:
params
:key
为数据库字段名,value
为字段值
null2IsNull
: 为true
则在map
的value
为null
时调用 isNull 方法,为false
时则忽略value
为null
的
- 例1:
allEq({id:1,name:"老王",age:null})
--->id = 1 and name = '老王' and age is null
- 例2:
allEq({id:1,name:"老王",age:null}, false)
--->id = 1 and name = '老王'
@Test
public void selectAllEq(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
Map<String,Object> params = new HashMap<String,Object>();
params.put("name","王天风");
params.put("age",25);
queryWrapper.allEq(params);
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
运行结果:
其他条件构造器的使用方法
selectMaps
有些时候返回的结果不需要是整个实体类的属性,可能只需要某几个字段的数据,如下:
@Test
public void selectByWrapperMaps(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("id","name").like("name","雨").lt("age",40);
List<Map<String,Object>> users = userMapper.selectMaps(queryWrapper);
users.forEach(System.out::println);
}
运行结果:
另外一种需求场景是统计查询。如下:
/**
* 11、按照直属上级分组,查询每组的平均年龄、最大年龄、最小年龄。
* 并且只取年龄总和小于500的组。
* select avg(age) avg_age,min(age) min_age,max(age) max_age
* from user
* group by manager_id
* having sum(age) <500
*/
@Test
public void selectByWrapperMaps2(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("avg(age) avg_age","min(age) min_age","max(age) max_age")
.groupBy("manager_id").having("sum(age)<{0}",500);
List<Map<String,Object>> users = userMapper.selectMaps(queryWrapper);
users.forEach(System.out::println);
}
运行结果:
selectObjs
只返回第一列的数据。
@Test
public void selectByObjs(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("id","name").like("name","雨").lt("age",40);
List<Object> users = userMapper.selectObjs(queryWrapper);
users.forEach(System.out::println);
}
运行结果:
selectCount
查询总记录数
@Test
public void selectWrapperCount(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("name","雨").lt("age",40);
int rows = userMapper.selectCount(queryWrapper);
System.out.println("总记录数:"+rows);
}
运行结果:
Lambda条件构造器
三种方法创建lambda
条件构造器:
LambdaQueryWrapper<User> lambda = ``new ``QueryWrapper<User>().lambda()``; ``LambdaQueryWrapper<User> userLambdaQueryWrapper = ``new ``LambdaQueryWrapper<User>()``; ``LambdaQueryWrapper<User> lambdaQuery =Wrappers.<User>``_lambdaQuery_``()``;
@Test
public void selectLambda(){
//LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();
//LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<User>();
LambdaQueryWrapper<User> lambdaQuery =Wrappers.<User>lambdaQuery();
lambdaQuery.like(User::getName,"雨").lt(User::getAge,40);
List<User> users = userMapper.selectList(lambdaQuery);
users.forEach(System.out::println);
}
运行结果:
@Test
public void selectLambda2(){
List<User> users = new LambdaQueryChainWrapper<User>(userMapper)
.like(User::getName, "雨").lt(User::getAge, 40).list();
users.forEach(System.out::println);
}
运行结果:
使用条件构造器的自定义SQL
MP版本需要大于3.0.7
首先在UserMapper类中自定义方法。如下:
@Mapper
public interface UserMapper extends BaseMapper<User> {
@Select("select * from user ${ew.customSqlSegment}")
List<User> selectAll(@Param(Constants.WRAPPER) Wrapper<User> wrappers);
}
注意:${ew.customSqlSegment}名字是固定写法。
编写测试方法
@Test
public void selectMy(){
LambdaQueryWrapper<User> lambdaQuery =Wrappers.<User>lambdaQuery();
lambdaQuery.like(User::getName,"雨").lt(User::getAge,40);
List<User> users = userMapper.selectAll(lambdaQuery);
users.forEach(System.out::println);
}
运行结果如下:
分页查询
MP分页插件实现物理分页
在项目目录中新建一个包,名字为config
,并创建一个类,名字为MyBatisPlusConfig
,内容如下:
package com.demo03.Config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
}
编写测试实现方法
@Test
public void selectPage(){
LambdaQueryWrapper<User> lambdaQuery =Wrappers.<User>lambdaQuery();
lambdaQuery.gt(User::getAge,20);
Page<User> userPage = new Page<>(1, 2);
Page<User> userPage1 = userMapper.selectPage(userPage, lambdaQuery);
System.out.println(userPage1);
}
AR模式、主键策略和基本配置
AR模式
Active Record(活动记录),是一种领域模型模式,特点是一个模型类对应关系型数据库中的一个表,而模型类的一个实例对应表中的一行记录。简单来说,就是通过实体类操作数据库的增删改查。
使用前提需要实体类继承Model类。如下:
package com.demo03.Entity;
import com.baomidou.mybatisplus.annotation.SqlCondition;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
@Data
@EqualsAndHashCode(callSuper = false)
public class User extends Model<User> {
//主键
private Long id;
//用户名
@TableField(condition = SqlCondition.LIKE)
private String name;
//邮箱
private String email;
//年龄
private Integer age;
//直属上级
private Long managerId;
//创建时间
private LocalDateTime createTime;
}
新建测试类
package com.demo03;
import com.demo03.Entity.User;
import com.demo03.Mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ARTests {
@Test
public void insert(){
User user = new User();
user.setName("马云");
user.setAge(37);
user.setEmail("jack@admin.com");
boolean rows = user.insert();
System.out.println("影响行数:"+rows);
}
}
主键策略
MP定义了6中主键策略。
@Getter
public enum IdType {
/**
* 数据库ID自增
*/
AUTO(0),
/**
* 该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
*/
NONE(1),
/**
* 用户输入ID
* <p>该类型可以通过自己注册自动填充插件进行填充</p>
*/
INPUT(2),
/* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */
/**
* 分配ID (主键类型为number或string),
* 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(雪花算法)
*
* @since 3.3.0
*/
ASSIGN_ID(3),
/**
* 分配UUID (主键类型为 string)
* 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(UUID.replace("-",""))
*/
ASSIGN_UUID(4),
/**
* @deprecated 3.3.0 please use {@link #ASSIGN_ID}
*/
@Deprecated
ID_WORKER(3),
/**
* @deprecated 3.3.0 please use {@link #ASSIGN_ID}
*/
@Deprecated
ID_WORKER_STR(3),
/**
* @deprecated 3.3.0 please use {@link #ASSIGN_UUID}
*/
@Deprecated
UUID(4);
private final int key;
IdType(int key) {
this.key = key;
}
}
局部主键策略实现
在实体类主键通过TableId注解方式。
@TableId(type = IdType.AUTO)
private Long id;
全局主键策略实现
在配置文件中配置全局主键ID。
mybatis-plus:
global-config:
db-config:
id-type: auto
MP基本配置
详细信息查看官网中的配置
MyBatisPlus 入门教程,这篇很赞的更多相关文章
- 最新hadoop入门教程汇总篇(附详细图文步骤)
关于hadoop的分享此前一直都是零零散散的想到什么就写什么,整体写的比较乱吧.最近可能还算好的吧,毕竟花了两周的时间详细的写完的了hadoop从规划到环境安装配置等全部内容.写过程不是很难,最烦的可 ...
- IOS开发入门教程-总结篇-写给狂热的编程爱好者们
程序发轻狂,代码阑珊,苹果开发安卓狂!--写给狂热的编程爱好者们 写在前面的话 学习iOS应用程序开发已有一段时间,最近稍微闲下来了,正好也想记录一下前阶段的整个学习过程.索性就从最基础的开始,一步一 ...
- Golang简易入门教程——面向对象篇
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是golang专题的第9篇文章,我们一起来看看golang当中的面向对象的部分. 在现在高级语言当中,面向对象几乎是不可或缺也是一门语言 ...
- Vue入门教程 第一篇 (概念及初始化)
注:为了本教程的准确性,部分描述引用了官网及网络内容. 安装Vue 1.使用npm安装vue: npm install vue 2.下载使用js文件: https://vuejs.org/js/vue ...
- Mybatis-plus入门教程(一)
什么是MyBatis-Plus MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发繁琐的CRUD.提高代码效率而生,同时 ...
- ASP.NET MVC4 新手入门教程特别篇之一----Code First Migrations更新数据库结构(数据迁移)修改Entity FrameWork 数据结构(不删除数据)
背景 code first起初当修改model后,要持久化至数据库中时,总要把原数据库给删除掉再创建(DropCreateDatabaseIfModelChanges),此时就会产生一个问题,当我们的 ...
- CodeIgniter 入门教程第一篇:信息发布
一.MVC CodeIgniter 采用MVC架构即:控制层.模型层和视图层. 对应Application下面的文件夹 (图1): 所有新建文件以.php结尾 视图层 view 文件夹放入HTML ...
- Vue入门教程 第二篇 (数据绑定与响应式)
数据绑定 Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统: <div id="app"> {{ message }} </ ...
- 【零基础】Selenium:Webdriver图文入门教程java篇(附相关包下载)
一.selenium2.0简述 与一般的浏览器测试框架(爬虫框架)不同,Selenium2.0实际上由两个部分组成Selenium+webdriver,Selenium负责用户指令的解释(code), ...
随机推荐
- MySQL 里有 2000w 数据,redis 中只存 20w 的数据,如 何保证 redis 中的数据都是热点数据?
Redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略. 相关知识:Redis 提供 6 种数据淘汰策略: volatile-lru:从已设置过期时间的数据集(server.db[i]. ...
- Redis 集群如何选择数据库?
Redis 集群目前无法做数据库选择,默认在 0 数据库.
- SQLAlchemy 使用教程
前戏: 不用怀疑,你肯定用过Django中的orm,这个orm框架是django框架中自己封装的,在Django中配置和使用较为简单,但是并不适用于其他web框架,而今天说的sqlalchemy是 ...
- scrapy --爬取媒体文件示例详解
scrapy 图片数据的爬取 基于scrapy进行图片数据的爬取: 在爬虫文件中只需要解析提取出图片地址,然后将地址提交给管道 配置文件中写入文件存储位置:IMAGES_STORE = './imgs ...
- Failed to write HTTP message,Could not write JSON错误
今天遇到使用@ResponseBody注解返回json数据时报错 Failed to write HTTP message: org.springframework.http.converter.Ht ...
- 【转载】10个Web3D可视化精彩案例
1.化学元素周期表 六种排列方式,炫酷动画效果,TWaver 3D轻松实现. 演示地址:http://demo.servasoft.com/che... 2.DNA螺旋图 DNA3D模型,包含几千个球 ...
- java中StringTokenizer的用法
4.StringTokenizer StringTokenizer可以解析分隔符不是空格的情况.例子:import java.util.StringTokenizer;public class Tes ...
- 安装并使用Junit
在Eclipse中配置Junit的方法有两种方式: 第一种方法: 1.下载junit的jar包,目前它的版本是junit3.8.1,可以从www.junit.org上下载. 2.在要使用Junit的p ...
- 第一阶段:Java基础之OOP
OOP:面向对象编程 三大特征: 封装 继承 多态
- 帝国CMS怎样删除清空数据库记录?
我用的帝国CMS,删除已经发表的文章和栏目后,后面新发的栏目和文章ID并不会重新从1开始,而是接着已经删除的文章和栏目ID,那么,怎样让后面发的文章和栏目ID重新从1开始呢? 首先,做任何重要修改前先 ...