MyBatisPlus

概述

官网:https://baomidou.com/

MyBatis-Plus (简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

MyBatisPlus可以节省我们大量的工作时间,所有的CRUD可以自动化完成。

JPA,tk-mapper,MyBatisPlus。

特性:

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
  • 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

快速入门

使用第三方插件:

  1. 导入对应的依赖
  2. 研究依赖如何配置
  3. 编写代码,拓展

步骤

  1. 创建数据库,mybaits_plus

  2. 创建user表

    1. DROP TABLE IF EXISTS user;
    2. CREATE TABLE user
    3. (
    4. id BIGINT(20) NOT NULL COMMENT '主键ID',
    5. name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
    6. age INT(11) NULL DEFAULT NULL COMMENT '年龄',
    7. email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
    8. PRIMARY KEY (id)
    9. );
    10. INSERT INTO user (id, name, age, email) VALUES
    11. (1, 'Jone', 18, 'test1@baomidou.com'),
    12. (2, 'Jack', 20, 'test2@baomidou.com'),
    13. (3, 'Tom', 28, 'test3@baomidou.com'),
    14. (4, 'Sandy', 21, 'test4@baomidou.com'),
    15. (5, 'Billie', 24, 'test5@baomidou.com');
    16. --真实开发中,version(乐观锁),deleted(逻辑删除),gmt_create,gmt_modified
  3. 初始化项目(使用SpringBoot初始化,导入依赖)

    1. <!--数据库驱动-->
    2. <dependency>
    3. <groupId>mysql</groupId>
    4. <artifactId>mysql-connector-java</artifactId>
    5. </dependency>
    6. <!--lombok-->
    7. <dependency>
    8. <groupId>org.projectlombok</groupId>
    9. <artifactId>lombok</artifactId>
    10. </dependency>
    11. <!--mybatis-plus-->
    12. <!--mybatis-plus是自己开发的,并非官方的-->
    13. <dependency>
    14. <groupId>com.baomidou</groupId>
    15. <artifactId>mybatis-plus-boot-starter</artifactId>
    16. <version>3.0.5</version>
    17. </dependency>

    mybatis-plus可以节省我们大量的代码,尽量不要同时导入mybatis和mybatis-plus!避免版本的差异!

  4. 连接数据库,和mybatis相同。

    application.properties

    1. # mysql5
    2. spring.datasource.username=root
    3. spring.datasource.password=123456
    4. spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&useSSL=false
    5. spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    6. #mysql8 驱动不同com.mysql.cj.jdbc.Driver(可兼容mysql5),需要配置时区 serverTimezone=GMT%2B8
  5. 传统方式:pojo-dao(连接mybatis,配置mapper.xml)-service-controller

  6. 使用mybatis-plus后,pojo-mapper接口-使用

    pojo

    1. package com.zr.pojo;
    2. @Data
    3. @AllArgsConstructor
    4. @NoArgsConstructor
    5. public class User {
    6. private Long id;
    7. private String name;
    8. private Integer age;
    9. private String email;
    10. }

    mapper接口

    1. package com.zr.mapper;
    2. //在对应的mapper上实现基本的类 BaseMapper
    3. @Repository //代表持久层的
    4. public interface UserMapper extends BaseMapper<User> {
    5. //所有的CRUD操作已经编写完成了
    6. //不需要配置其它文件了
    7. }

    主启动类

    1. package com.zr;
    2. //扫描mapper文件夹
    3. @MapperScan("com.zr.mapper")
    4. @SpringBootApplication
    5. public class MybatisPlusApplication {
    6. public static void main(String[] args) {
    7. SpringApplication.run(MybatisPlusApplication.class, args);
    8. }
    9. }

    测试

    1. package com.zr;
    2. @SpringBootTest
    3. class MybatisPlusApplicationTests {
    4. //继承了BaseMapper,所有的方法都来自于父类
    5. //我们也可以编写自己的拓展方法
    6. @Autowired
    7. private UserMapper userMapper;
    8. @Test
    9. void contextLoads() {
    10. //参数是一个 Wrapper,条件构造器,这里先不用 null
    11. //查询全部用户
    12. List<User> users = userMapper.selectList(null);
    13. users.forEach(System.out::println);
    14. }
    15. }

注意点:主启动类上扫描mapper下的所有接口。

配置日志输出

我们所有的sql现在是不可见的,我们希望知道它是怎么执行的,就必须看日志。

application.properties中增加

  1. #配置日志
  2. mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

日志输出结果:

CRUD拓展

插入

  1. package com.zr;
  2. @SpringBootTest
  3. class MybatisPlusApplicationTests {
  4. //继承了BaseMapper,所有的方法都来自于父类
  5. //我们也可以编写自己的拓展方法
  6. @Autowired
  7. private UserMapper userMapper;
  8. //测试插入
  9. @Test
  10. public void testInsert(){
  11. User user = new User();
  12. user.setName("周周");
  13. user.setAge(20);
  14. user.setEmail("813794474@qq.com");
  15. userMapper.insert(user); //自动生成ID
  16. System.out.println(user.toString());
  17. }
  18. }

测试结果:

数据库插入ID的默认值为:全局唯一的ID。

主键生成策略

可查询分布式系统唯一id生成解决方案。

雪花算法:SnowFlake 算法,是 Twitter 开源的分布式 id 生成算法(long型的ID)。其核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 id,其中41bit作为毫秒数,10bit作为机器的id(5bit是数据中心,5bit是机器id),12bit作为毫秒内的流水号(意味着每个节点在每秒可产生4096个ID),最后有一位符号位,永远是0。在分布式系统中的应用十分广泛,且ID 引入了时间戳,基本上保持自增的。

主键配置:

字段上加 @TableId(type = IdType.AUTO)

数据库字段一定要是递增。

  1. package com.zr.pojo;
  2. @Data
  3. @AllArgsConstructor
  4. @NoArgsConstructor
  5. public class User {
  6. //对应数据库中的主键(uuid,自增id,雪花算法,redis,zookeeper)
  7. @TableId(type = IdType.AUTO)
  8. private Long id;
  9. private String name;
  10. private Integer age;
  11. private String email;
  12. }

测试插入。

源码:

  1. public enum IdType {
  2. AUTO(0), //数据库id自增
  3. NONE(1), //未设置主键
  4. INPUT(2), //手动输入
  5. ID_WORKER(3), //默认的全局唯一id
  6. UUID(4), //全局唯一id
  7. ID_WORKER_STR(5); // ID_WORKER的字符串表示法
  8. }

更新操作

测试方法中添加:

  1. //更新
  2. @Test
  3. public void testUpdate(){
  4. User user = new User();
  5. user.setId(22L);
  6. user.setName("周周zzzz");
  7. user.setAge(20);
  8. userMapper.updateById(user);
  9. }

sql自动动态配置

自动填充

创建时间,修改时间!这些操作都是自动化完成的,我们不希望手动更新。

阿里巴巴开发手册:所有的数据库,gmt_creat,gmt-modified几乎所有的表都要配置上,而且需要自动化。

方式一:数据库级别(工作中不允许修改数据库的,不建议使用)

  1. 在表中新增字段,create_time,update_time(create_time不勾选根据当前时间更新)

  2. 再次测试插入方法,需要先把实体类同步!

    1. private Date createTime;
    2. private Date updateTime;
  3. 再次测试更新操作。

方式二:代码级别

  1. 删除时间的默认值

  2. 实体类字段属性上需要增加注解

    1. //字段插入填充内容
    2. @TableField(fill = FieldFill.INSERT)
    3. private Date createTime;
    4. @TableField(fill = FieldFill.INSERT_UPDATE)
    5. private Date updateTime;
  3. 编写处理器来处理注解

    1. package com.zr.handler;
    2. @Slf4j
    3. @Component //加到IOC容器中
    4. public class MyMetaObjectHandler implements MetaObjectHandler {
    5. //插入时的填充策略
    6. @Override
    7. public void insertFill(MetaObject metaObject) {
    8. log.debug("start insert....");
    9. this.setFieldValByName("createTime",new Date(),metaObject);
    10. this.setFieldValByName("updateTime",new Date(),metaObject);
    11. }
    12. //更新时的填充策略
    13. @Override
    14. public void updateFill(MetaObject metaObject) {
    15. log.debug("start update....");
    16. this.setFieldValByName("updateTime",new Date(),metaObject);
    17. }
    18. }
  4. 测试插入,观察时间更新。

乐观锁

乐观锁:顾名思义非常乐观,总是认为不会出现问题,无论干什么都不去上锁,如果出现了问题,再次更新值测试。

悲观锁:顾名思义非常悲观,总是认为会出现问题,无论干什么都加锁,再去操作。

乐观锁实现方式:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败
  1. 乐观锁,先查询,获取版本号
  2. ---A
  3. update user set name = "zhour",version=version+1
  4. where id = 2 and version = 1
  5. ---B 线程先完成,这个时候versioon=2A执行失败
  6. update user set name = "zhour",version=version+1
  7. where id = 2 and version = 1

测试乐观锁MP插件:

数据库中增加version字段

同步实体类

  1. //乐观锁的注解
  2. @Version
  3. private Integer version;

注册组件(主启动类的扫描mapper放到这里)MyBatisPlusConfig

  1. package com.zr.config;
  2. //扫描mapper文件夹
  3. @MapperScan("com.zr.mapper")
  4. @EnableTransactionManagement
  5. @Configuration //代表是一个配置类
  6. public class MyBatisPlusConfig {
  7. //注册乐观锁插件
  8. @Bean
  9. public OptimisticLockerInterceptor optimisticLockerInterceptor(){
  10. return new OptimisticLockerInterceptor();
  11. }
  12. }

测试:添加以下代码

  1. //测试乐观锁成功
  2. @Test
  3. public void testOptimisticLocker(){
  4. //线程1
  5. //查询用户信息
  6. User user = userMapper.selectById(222L);
  7. //修改用户信息
  8. user.setName("zhourrr");
  9. user.setEmail("813794474@qq.com");
  10. //执行更新操作
  11. userMapper.updateById(user);
  12. }
  13. //测试乐观锁失败,多线程下
  14. @Test
  15. public void testOptimisticLocker2(){
  16. //线程1
  17. User user1 = userMapper.selectById(222L);
  18. user1.setName("zhourrr111");
  19. user1.setEmail("813794474@qq.com");
  20. //模拟另外一个线程执行了插队操作
  21. User user2 = userMapper.selectById(222L);
  22. user2.setName("zhourrr222");
  23. user2.setEmail("813794474@qq.com");
  24. userMapper.updateById(user2);
  25. //自旋锁来多次尝试提交
  26. userMapper.updateById(user1); //如果没有乐观锁就会覆盖插队线程的值
  27. }

查询操作

  1. //测试批量查询
  2. @Test
  3. public void testSelectById(){
  4. User user = userMapper.selectById(222L);
  5. System.out.println(user);
  6. }
  7. @Test
  8. public void testSelectBatchIds(){
  9. List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
  10. // System.out.println(users);
  11. users.forEach(System.out::println);
  12. }
  13. //按条件查询 Map
  14. @Test
  15. public void testSelectByMap(){
  16. HashMap<String,Object> map = new HashMap();
  17. //自定义查询
  18. map.put("name","周周zzzz");
  19. List<User> users = userMapper.selectByMap(map);
  20. users.forEach(System.out::println);
  21. }

分页查询

分页在网站的使用非常多。

  1. 原始用limit分页
  2. pageHelper 第三方插件
  3. MP内置了分页插件

使用:

  1. 配置拦截器组即可(官网示例)

    MyBatisPlusConfig中添加

    1. //分页插件
    2. @Bean
    3. public PaginationInterceptor paginationInterceptor() {
    4. return new PaginationInterceptor;
    5. }
  2. 直接使用page对象即可

    1. //测试分页查询
    2. @Test
    3. public void testPage(){
    4. //参数1:当前页
    5. //参数2:页面的大小
    6. Page<User> page = new Page<>(1,5);
    7. userMapper.selectPage(page,null);
    8. page.getRecords().forEach(System.out::println);
    9. System.out.println(page.getTotal());
    10. }

删除操作

根据id删除

  1. //测试删除
  2. @Test
  3. public void testDeleteById(){
  4. userMapper.deleteById(1342445919922073602L);
  5. }
  6. //通过id批量删除
  7. @Test
  8. public void testDeleteBatchByIds(){
  9. userMapper.deleteBatchIds(Arrays.asList(1342445919922073602L,222));
  10. }
  11. //通过Map删除
  12. @Test
  13. public void testDeleteByMap(){
  14. HashMap<String, Object> map = new HashMap<>();
  15. map.put("name","zhourrr222");
  16. userMapper.deleteByMap(map);
  17. }

逻辑删除

物理删除:从数据库中直接移除

逻辑删除:在数据库中没有被移除,而是通过一个变量让它失效

应用:管理员可以查看被删除的内容,防止数据的丢失,类似于回收站!

测试:

  1. 在数据库中增加一个deleted字段

  2. 实体类中增加属性

    1. @TableLogic //逻辑删除注解
    2. private Integer deleted;
  3. 配置 MyBatisPlusConfig

    1. //逻辑删除组件
    2. @Bean
    3. public ISqlInjector sqlInjector(){
    4. return new LogicSqlInjector();
    5. }

    application.properties中添加

    1. #配置逻辑删除
    2. # 逻辑已删除值(默认为 1)
    3. # 逻辑未删除值(默认为 0)
    4. mybatis-plus.global-config.db-config.logic-delete-value=1
    5. mybatis-plus.global-config.db-config.logic-not-delete-value=0
  4. 测试

观察数据库中id为111的用户deleted的值变为1.

再次查询id为111的用户,显示为空(只会查询deleted值为0的用户)。

性能分析插件

在开发中,我们会遇到一些慢sql。测试,durid....

MP也提供了性能分析插件,如果超过这个时间就停止运行。

  1. 导入插件

    1. //sql执行效率插件
    2. @Bean
    3. @Profile({"dev","test"}) //设置dev,test环境开启
    4. public PerformanceInterceptor performanceInterceptor(){
    5. PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
    6. performanceInterceptor.setMaxTime(100); //设置sql能够执行的最大时间
    7. performanceInterceptor.setFormat(true); //是否格式化sql语句
    8. return performanceInterceptor;
    9. }

    在application.properties中配置环境为测试或者开发环境。

    1. #设置开发环境
    2. spring.profiles.active=dev
  2. 测试使用

    1. @Test
    2. void contextLoads() {
    3. //参数是一个 Wrapper,条件构造器,这里先不用 null
    4. //查询全部用户
    5. List<User> users = userMapper.selectList(null);
    6. users.forEach(System.out::println);
    7. }

sql执行的时间和格式化的sql

执行的时间超过了设定的时间就会抛出异常。

使用性能分析插件可以帮助我们提高效率!

条件构造器

AbstractWrapper.

我们写一些复杂的sql就可以使用它来替代。

新建一个测试类 WrapperTest。

以下的测试结合日志的 SQL 语句来分析。

测试一:查询name不为空的用户,并且邮箱也不为空,且年龄大于12的用户

  1. package com.zr;
  2. @SpringBootTest
  3. public class WrapperTest {
  4. @Autowired
  5. private UserMapper userMapper;
  6. @Test
  7. void contextLoads() {
  8. //查询name不为空的用户,并且邮箱也不为空,且年龄大于12的用户
  9. QueryWrapper<User> wrapper = new QueryWrapper<>();
  10. wrapper
  11. .isNotNull("name")
  12. .isNotNull("email")
  13. .ge("age",12);
  14. userMapper.selectList(wrapper).forEach(System.out::println);
  15. }
  16. }

测试二:查询名字为周周zzzz的用户

  1. @Test
  2. void test2(){
  3. //查询名字为周周zzzz的用户
  4. QueryWrapper<User> wrapper = new QueryWrapper<>();
  5. wrapper.eq("name","周周zzzz");
  6. User user = userMapper.selectOne(wrapper); //查询一个数据,查询多个用list或者map
  7. System.out.println(user);
  8. }

测试三:查询年龄在10-20之间的用户

  1. @Test
  2. void test3(){
  3. //查询年龄在10-20之间的用户
  4. QueryWrapper<User> wrapper = new QueryWrapper<>();
  5. wrapper.between("age",10,20);
  6. userMapper.selectCount(wrapper); //查询结果数
  7. }

测试四:查询名字中没有字母e,且邮箱是以t开头的(t%)

  1. @Test
  2. void test4(){
  3. //模糊查询
  4. QueryWrapper<User> wrapper = new QueryWrapper<>();
  5. wrapper
  6. .notLike("name","e")
  7. .likeRight("email","t");
  8. List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
  9. maps.forEach(System.out::println);
  10. }

测试五:子查询

  1. @Test
  2. void test5(){
  3. // id 在子查询中查出来
  4. QueryWrapper<User> wrapper = new QueryWrapper<>();
  5. wrapper.inSql("id","select id from user where id < 3");
  6. List<Object> objects = userMapper.selectObjs(wrapper);
  7. objects.forEach(System.out::println);
  8. }

测试六:通过 id 降序排序

  1. @Test
  2. void test6(){
  3. // 通过 id 降序排序
  4. QueryWrapper<User> wrapper = new QueryWrapper<>();
  5. wrapper.orderByDesc("id");
  6. List<User> users = userMapper.selectList(wrapper);
  7. users.forEach(System.out::println);
  8. }

其它更多测试参考mybatis-plus官方文档。

代码自动生成器

AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。

  1. package com.zr;
  2. public class ZrCode {
  3. public static void main(String[] args) {
  4. //代码自动生成
  5. AutoGenerator mpg = new AutoGenerator();
  6. //全局配置
  7. GlobalConfig gc = new GlobalConfig();
  8. String projectPath = System.getProperty("user.dir");
  9. gc.setOutputDir(projectPath+"/src/main/java");
  10. gc.setAuthor("zhour");
  11. gc.setOpen(false);
  12. gc.setFileOverride(false); //是否覆盖
  13. gc.setServiceName("%sService"); //去Service的 i 前缀
  14. gc.setIdType(IdType.ID_WORKER);
  15. gc.setDateType(DateType.ONLY_DATE);
  16. gc.setSwagger2(true);
  17. mpg.setGlobalConfig(gc);
  18. //数据源配置
  19. DataSourceConfig ds = new DataSourceConfig();
  20. ds.setUrl("jdbc:mysql://localhost:3306/mybaits_plus?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT");
  21. ds.setDriverName("com.mysql.cj.jdbc.Driver");
  22. ds.setUsername("root");
  23. ds.setPassword("123456");
  24. ds.setDbType(DbType.MYSQL);
  25. mpg.setDataSource(ds);
  26. //包的配置
  27. PackageConfig pc = new PackageConfig();
  28. pc.setModuleName("blog");
  29. pc.setParent("com.zrcode");
  30. pc.setEntity("entity");
  31. pc.setMapper("mapper");
  32. pc.setController("controller");
  33. pc.setService("service");
  34. mpg.setPackageInfo(pc);
  35. //策略配置
  36. StrategyConfig strategy = new StrategyConfig();
  37. strategy.setInclude("user"); //设置要映射的表名
  38. strategy.setNaming(NamingStrategy.underline_to_camel); //转驼峰命名
  39. strategy.setColumnNaming(NamingStrategy.underline_to_camel); //转驼峰命名
  40. strategy.setEntityLombokModel(true);
  41. strategy.setLogicDeleteFieldName("deleted"); //逻辑删除
  42. //自动填充
  43. TableFill createTime = new TableFill("create_time", FieldFill.INSERT);
  44. TableFill updateTime = new TableFill("update_time", FieldFill.INSERT_UPDATE);
  45. ArrayList<TableFill> list = new ArrayList<>();
  46. list.add(createTime);
  47. list.add(updateTime);
  48. strategy.setTableFillList(list);
  49. //乐观锁
  50. strategy.setVersionFieldName("version");
  51. strategy.setRestControllerStyle(true);
  52. strategy.setControllerMappingHyphenStyle(true); //localhost:8080/hello_id_3,下划线命名
  53. mpg.setStrategy(strategy);
  54. mpg.execute();
  55. }
  56. }

本文项目结构目录:

MyBatisPlus入门学习的更多相关文章

  1. Mybatis-plus入门学习]

    需要的数据库建表语句: #创建用户表 CREATE TABLE user ( id BIGINT(20) PRIMARY KEY NOT NULL COMMENT '主键', name VARCHAR ...

  2. Mybatis-Plus入门学习笔记(一)

    本文内容 了解Mybatis-Plus 整合Mybatis-Plus 1.了解Mybatis-plus 1.1.Mybatis-Plus介绍 MyBatis-Plus(简称 MP)是一个 MyBati ...

  3. Java开发学习(四十)----MyBatisPlus入门案例与简介

    一.入门案例 MybatisPlus(简称MP)是基于MyBatis框架基础上开发的增强型工具,旨在简化开发.提供效率. SpringBoot它能快速构建Spring开发环境用以整合其他技术,使用起来 ...

  4. 【原创】SpringBoot & SpringCloud 快速入门学习笔记(完整示例)

    [原创]SpringBoot & SpringCloud 快速入门学习笔记(完整示例) 1月前在系统的学习SpringBoot和SpringCloud,同时整理了快速入门示例,方便能针对每个知 ...

  5. vue入门学习(基础篇)

    vue入门学习总结: vue的一个组件包括三部分:template.style.script. vue的数据在data中定义使用. 数据渲染指令:v-text.v-html.{{}}. 隐藏未编译的标 ...

  6. Hadoop入门学习笔记---part4

    紧接着<Hadoop入门学习笔记---part3>中的继续了解如何用java在程序中操作HDFS. 众所周知,对文件的操作无非是创建,查看,下载,删除.下面我们就开始应用java程序进行操 ...

  7. Hadoop入门学习笔记---part3

    2015年元旦,好好学习,天天向上.良好的开端是成功的一半,任何学习都不能中断,只有坚持才会出结果.继续学习Hadoop.冰冻三尺,非一日之寒! 经过Hadoop的伪分布集群环境的搭建,基本对Hado ...

  8. PyQt4入门学习笔记(三)

    # PyQt4入门学习笔记(三) PyQt4内的布局 布局方式是我们控制我们的GUI页面内各个控件的排放位置的.我们可以通过两种基本方式来控制: 1.绝对位置 2.layout类 绝对位置 这种方式要 ...

  9. PyQt4入门学习笔记(一)

    PyQt4入门学习笔记(一) 一直没有找到什么好的pyqt4的教程,偶然在google上搜到一篇不错的入门文档,翻译过来,留以后再复习. 原始链接如下: http://zetcode.com/gui/ ...

随机推荐

  1. Markdown的基本用法与下载

    Markdown的基本用法与下载typora 下载typora 1.在浏览器搜索typora 2.然后点进去 3.往下翻点击Download 4.看自己是什么系统然后在选择 5.选好系统以后再去去选择 ...

  2. Course2.1 Graph Paper Programming

    Overview 通过日常生活中的活动来体验程序算法,目标时能够将现实世界的场景与程序场景关联起来. Objective 抓住将现实世界问题转换为程序的难点: 你认为非常明确的指令在计算机看来可能还是 ...

  3. 如何快速开发Winform应用系统

    在实际的业务中,往往还有很多需要使用Winform来开发应用系统的,如一些HIS.MIS.MES等系统,由于Winform开发出来的系统界面友好,响应快速,开发效率高等各方面原因,还有一些原因是独立的 ...

  4. Java基础 随笔整理

    Java基础随笔整理 为了方便阅读,特整理了相关的学习笔记 Java感想 操千曲而后晓声 Java入门 Java其他 Java虚拟机详解 语言入门百题 Java开发工具 · Eclipse Java语 ...

  5. JVM笔记 -- JVM的生命周期介绍

    Github仓库地址:https://github.com/Damaer/JvmNote 文档地址:https://damaer.github.io/JvmNote/ JVM生命周期 启动 执行 退出 ...

  6. 为什么要从 Linux 迁移到 BSD 4

    为什么要从 Linux 迁移到 BSD 4 许可证问题 Linux GPL 许可证对开发者的要求比较严格,它是一种开源的反模式,因为它强制发布所有修改过的源代码,并且阻止其他开源项目的集成,例如 GP ...

  7. 解决图片把父元素向下撑大大约3px问题

    现象  bug: 图片在div\li\dt 等  图片把父元素向下撑大大约3px  <style>         img {             width: 30%; //这里由于 ...

  8. ch2_8_3求解回文序列问题(递归实现)

    思路:回文序列中左右两边的值一定相等,所以可以将该问题分解为两边化为相同元素操作的次数和去掉两边相等元素后后剩下元素变成回文序列的操作次数. 题目: 如果一个数字序列逆置之后跟原序列是一样的就称这样的 ...

  9. 获得PyInstaller打包exe的py源码

     参考链接:https://laucyun.com/33359ed9f725529ac9b606d054c8459d.html way1:pyi-archive_viewer 提取pyc,uncomp ...

  10. PTA 两个有序链表序列的合并

    6-5 两个有序链表序列的合并 (15 分)   本题要求实现一个函数,将两个链表表示的递增整数序列合并为一个非递减的整数序列. 函数接口定义: List Merge( List L1, List L ...