首页
碎碎念
东邻西舍
本站信息
前来吐槽
统计
Search
1
openwrt系统上安装第三方插件
26,761 阅读
2
ubuntu下zerotier的基本使用教程
13,581 阅读
3
给小米R3G更换系统:从padavan刷成openwrt
12,849 阅读
4
openwrt使用第一步:设置上网拨号
10,744 阅读
5
openwrt无线中继功能:实现不插网线就能上网
9,522 阅读
学习点滴
Java
Web前端
Linux
踩坑实录
折腾搞机
关于建站
只言片语
登录
Search
标签搜索
Linux
建站
Java
踩坑实录
Ubuntu
MySQL
折腾搞机
HTML
CSS
MyBatis
Spring
SQL
Nginx
路由器
树莓派
OpenWrt
Maven
Git
Win10
只言片语
知识分子没文化
累计撰写
83
篇文章
累计收到
152
条评论
首页
栏目
学习点滴
Java
Web前端
Linux
踩坑实录
折腾搞机
关于建站
只言片语
页面
碎碎念
东邻西舍
本站信息
前来吐槽
统计
搜索到
50
篇与
的结果
2021-11-05
Spring学习笔记(一) - Bean与依赖注入
目录: 一、Spring简介 二、Bean配置 2.1、基础配置 2.2、别名配置 2.3、作用域 三、Bean的生命周期 3.1、实例化 3.2、属性赋值 3.3、初始化 3.4、使用 3.5、销毁 3.6、示例:通过XML配置自定义初始化和销毁操作 四、实例化Bean的方式 4.1、无参构造方法 4.2、静态工厂 4.3、实例工厂 4.3.1、方式一 4.3.2、方式二(重要) 五、依赖注入(DI) 5.1、setter 注入 5.1.1、注入简单类型 5.1.2、注入引用类型 5.2、构造器注入 5.2.1、注入简单类型 5.2.2、注入引用类型 5.2.3、构造器注入的其他XML配置写法 5.2.3.1、type方式 4.2.3.2、index索引方式 5.3、基于XML文件的自动装配 5.3.1、byType 5.3.2、byName 5.3.3、constructor 5.4、基于注解的自动装配 六、集合的注入 6.1、注入数组 6.2、注入 Set 对象 6.3、注入 List 对象 6.4、注入 Map 类型数据 6.5、注入 property 类型数据 七、Spring容器的核心操作 7.1、创建容器 7.2、从Srping容器获取Bean 7.2.1、根据Bean名称/ID 7.2.2、根据Bean类型获取 7.2.3、根据Bean名称获取并指定类型 八、一图流总结 8.1、Bean: 8.2、依赖注入: 一、Spring简介 Spring 是一个开源的 Java 平台框架,广泛用于构建企业级应用程序。它由 Rod Johnson 在 2003 年首次发布,旨在简化 Java 开发,提供全面的基础设施支持。Spring 的核心特性包括依赖注入(DI)和面向切面编程(AOP),是开发Java EE应用程序的必备。 在 pom.xml 文件中导入 Spring 的坐标依赖: <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency> 二、Bean配置 Bean 是 Spring 框架中最核心的概念之一,它是构成应用程序主干并由 Spring IoC 容器管理的对象。 Spring Bean 本质上是由 Spring IoC 容器实例化、组装和管理的对象,可以是任何 Java 类的实例,如一个简单的 POJO(Plain Old Java Object),比如一个表示用户信息的 User 类,在 Spring 容器中可以被定义为一个 Bean,然后 Spring 可以对 User 类的实例进行各种诸如依赖注入等的管理操作。除此之外,Bean 也可以是一个复杂的企业级组件。 在 Java 中,对象通常通过 new 关键字来创建,但在 Spring 中,对象的创建和依赖注入由 Spring IoC 容器负责。这种机制允许开发者将对象的生命周期管理和依赖关系交给 Spring 容器,从而简化了开发过程并提高了代码的可维护性和灵活性。 2.1、基础配置 <!-- bean标签用来配置bean id属性是bean的名字,是唯一的,不能重复 class属性是bean的类型,值是全路径类名 --> <bean id="userDao" class="com.wlplove.dao.impl.UserDaoImpl"/> <bean id="userService" class="com.wlplove.service.impl.UserServiceImpl"> <!-- property标签用来配置当前bean中的的属性,需要其有set方法 name属性指定配置的哪一个属性,是属性的名称 ref属性表示参照哪一个bean,是当前容器中存在的bean --> <property name="userDao" ref="userDao"/> </bean> 在 XML 文件中经过上面的配置之后,就将这个类交给了 Spring IoC 容器进行管理,之后需要使用该类时就可以从容器中获取到实例对象了。 2.2、别名配置 name 属性表示 Bean 的别名,可以设置多个,使用逗号、分号、空格分开。 别名配置完成后,就可以通过别名获取 Bean 或者在其他 Bean 的配置中通过别名引用这个 Bean。 <bean id="bookService" name="service service2 bookEbi" class="com.wlplove.service.impl.BookServiceImpl"/> 2.3、作用域 Spring Bean 的 Scope 指的是 Bean 的作用域,它定义了 Bean 实例在 Spring 容器中的生命周期和可见性。一般常用的是 singleton(单例)、prototype(原型/非单例): singleton:默认作用域,Spring 容器只会创建一个 Bean 实例,并在整个应用程序中共享。这个实例从容器启动时被初始化,直到容器销毁才会被释放。这种模式适用于无状态的服务对象,如 DAO 组件、控制器等。 prototype:每次请求 Bean 时都会创建一个新的实例。这些实例由 Spring 容器创建,但容器不会跟踪它们的管理和销毁,这些任务交由 Java 的垃圾回收机制来处理。适用于需要频繁创建且生命周期较短的 Bean,如用户会话数据对象。 作用域可以通过 XML 配置: <bean id="bookDao" class="com.wlplove.dao.impl.BookDaoImpl" scope="singleton"/> 也可以使用注解 @Scope 定义作用域: public class AppConfig { // @Scope("prototype") @Scope("singleton") public MyBean myBean() { return new MyBean(); } } 除此之外,还有 request、session、application 等作用域。 三、Bean的生命周期 Spring Bean 的生命周期包括实例化、属性赋值、初始化、使用和销毁五个阶段。 3.1、实例化 实例化指的是由 Spring 容器创建 Bean 实例的过程。 在这个阶段,Spring 容器通过反射机制来创建 Bean 的实例。 3.2、属性赋值 Spring 容器根据 Bean 信息,为 Bean 的属性进行赋值操作。 这一阶段通常涉及到依赖注入(DI),Spring 容器会自动填充 Bean 的属性并将其他 Bean 的引用注入到当前 Bean 的属性中。 3.3、初始化 初始化阶段是 Spring Bean 生命周期中的一个重要环节,它标志着 Bean 已经准备好被使用。 在这个阶段,Spring 容器会执行一系列初始化操作,其中包括开发者自定义的初始化方法,开发者可以通过以下几种方式自定义初始化操作: XML 配置时在 <bean> 标签中定义属性 init-method 使用 @PostConstruct 注解定义初始化方法 实现接口 InitializingBean 的 afterPropertiesSet() 方法 3.4、使用 这一阶段,Bean 已经被完全初始化,并且可以被 Spring 容器提供给其他组件或服务进行调用。Bean 的使用通常是通过依赖注入(DI)的方式完成的,即在需要使用 Bean 的地方直接注入即可。 3.5、销毁 销毁阶段是 Spring Bean 生命周期的最后一个阶段,它发生在 Bean 不再被需要时。 在这个阶段,Spring 容器会执行一系列的清理操作,包括开发者自定义的 Bean 的销毁方法,开发者可以通过以下几种方式: XML 配置时在 <bean> 标签中定义 destroy-method 属性 使用 @PreDestroy 注解定义销毁方法 实现接口 DisposableBean 的 destroy() 方法 这些操作旨在释放 Bean 所占用的资源,确保系统的稳定性和性能。 3.6、示例:通过XML配置自定义初始化和销毁操作 Java 代码: public class UserServiceImpl implements UserService { @Override public void save() { System.out.println("save ..."); } publid void init() { System.out.println("init ...."); } public void destory() { System.out.println("destory ..."); } } XML 配置: <!-- “init-method”方法指定Bean的初始化方法,“destory-method”方法指定Bean的销毁方法 --> <bean id="userService" class="com.wlplove.service.impl.UserServiceImpl" init-method="init" destroy-method="destory" /> 四、实例化Bean的方式 4.1、无参构造方法 Java 类: public class UserServiceImpl implements UserService { private UserServiceImpl() { System.out.println("constructor is running ...."); } public void save() { System.out.println("save ..."); } } Spring 配置: <bean id="userService" class="com.wlplove.service.impl.UserServiceImpl"/> 在接口继承类中必须要提供无参构造方法,如果不存在,将抛出 BeanCreationException 异常 4.2、静态工厂 Java 类: public class UserServiceImpl implements UserService { // ... } // 工厂类 public class UserServiceFactory { // 静态工厂方法 public static UserService getUserService() { return new UserServiceImpl(); } } Spring 配置: <!-- class属性指定工厂类,factory-method属性指定使用工厂类中的哪个静态方法实例化Bean --> <bean id="userService" class="com.wlplove.factory.UserServiceFactory" factory-method="getUserService"/> 4.3、实例工厂 4.3.1、方式一 Java 类: // 工厂类 public class UserServiceFactory { // 工厂方法(非静态) public UserService getUserService() { return new UserServiceImpl(); } } Spring 配置: <!-- 工厂Bean --> <bean id="userServiceFactory" class="com.wlplove.factory.UserServiceFactory" /> <!-- 用前面定义好的工厂类userServiceFactory中的方法getUserService来实例化userService --> <!-- factory-bean 指定工厂类,factory-method 方法指定用工厂类的哪个方法实例化 Bean --> <bean id="userService" factory-bean="userServiceFactory" factory-method="getUserService" /> 4.3.2、方式二(重要) 工厂对象继承 FactoryBean<T> 这个对象,并重写其中的 getObject() 和 getObjectType() 方法 FactoryBean 是 Spring 框架中用于创建复杂对象的一个特殊接口,它允许开发者创建一个工厂类,用于生成其他对象。这个接口定义了三个主要方法: getObject() 作用:返回由该 FactoryBean 创建的对象实例。这是 FactoryBean 最核心的方法,用于实际创建对象实例。 注意:这个方法可能会抛出异常,因为对象的创建过程可能涉及复杂的逻辑和资源管理。 getObjectType() 作用:返回由该 FactoryBean 创建的对象的类型。这有助于 Spring 容器在运行时了解 Bean 的类型信息,从而进行类型匹配和依赖注入。 默认实现:如果未重写此方法,则默认返回 Object.class。 isSingleton() 作用:指定返回的实例是否为单例。如果返回 true,则表示这个 FactoryBean 返回的对象在整个 Spring 容器中是唯一的;如果返回 false,则每次请求都会创建一个新的实例。 默认实现:如果没有明确指定,默认返回 true,即单例模式。 Java 类: // 省略 UserService 接口与 UserServiceImpl 继承类的定义... public class UserServiceFactoryBean implements FactoryBean<UserService> { @Override public UserServce getObject() throws Exception { return new UserServiceImpl(); } @Override public Class<?> getObjectType() { return UserService.class; } @Override public boolean isSingleton() { // true 返回单例对象,false 返回非单例对象 return ture; } } Spring 配置: <bean id="userService" class="com.wlplove.factory.UserServiceFactoryBean" /> 五、依赖注入(DI) 依赖注入(Dependency Injection,简称 DI)是 Spring 框架的核心概念之一,这种设计模式用于实现控制反转(Inversion of Control,即 IoC)。它的核心思想是:对象的依赖关系由外部容器(如 Spring 容器)在运行时注入,而不是由对象自己创建或查找依赖。 举个例子,假设有一个 UserService 类,它依赖于 UserRepository 类。在没有依赖注入的情况下,UserService 需要自己创建 UserRepository 的实例。这种方式的问题在于,UserService 和 UserRepository 紧密耦合在一起,难以测试和维护。 使用依赖注入后,UserService 不再自己创建 UserRepository,而是通过构造函数、Setter 方法或自动装配的方式,由 Spring 容器提供 UserRepository 的实例。 Spring 提供了三种主要的依赖注入方式:setter 注入、构造器注入、自动装配。 5.1、setter 注入 5.1.1、注入简单类型 Java 类中提供成员的 set 方法: public class User { // 姓名 private String name; // 年龄 private int age; public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } } Spring 配置中用 <property> 标签来定义具体成员: <!-- 简单类型 (通过 value 属性注入普通类型值) --> <bean id="user" class="com.wlplove.dto.User"> <property name="name" value="test" /> <property name="age" value="20" /> </bean> 5.1.2、注入引用类型 同样的,在 Java 类中提供对象的 set 方法: // 省略接口UserDao接口的定义 ... // 接口继承类 public class UserServiceImpl implements userService { private UserDao userDao; private setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public void save() { userDao.insert(); } } Spring 配置: <bean id="userDao" class="com.wlplove.dao.UserDao" /> <!-- 引用类型 (通过 ref 属性注入引用类型值) --> <bean id="userServiceImpl" class="com.wlplove.service.UserServiceImpl"> <property name="userDao" ref="userDao" /> </bean> 5.2、构造器注入 在对象创建时,所有的依赖都通过构造器参数传入,类似于 setter 注入需要提供成员 set 方法,构造方法注入需要在类中提供构造方法,并且 XML 配置里使用构造器注入的参数顺序必须要与 Java 类构造方法的形参顺序相同。 5.2.1、注入简单类型 构造方法: public class User { // 姓名 private String name; // 年龄 private int age; public void User(String name, int age) { this.name = name; this.age = age; } } Spring 配置: <!-- 普通类型 (通过 value 属性注入引用类型值,name属性值是构造方法中的形参)--> <bean id="user" class="com.wlplove.dto.User"> <!-- 这里的参数顺序要与构造函数中的形参顺序相同 --> <construct-arg name="name" value="test" /> <construct-arg name="age" value="20" /> </bean> 5.2.2、注入引用类型 // 接口继承类 public class UserServiceImpl implements userService { private UserDao userDao; private UserServiceImpl(UserDao userDao) { this.userDao = userDao; } @Override public void save() { userDao.insert(); } } Spring 配置: <bean id="userDao" class="com.wlplove.dao.UserDao" /> <!-- 引用类型 (通过 ref 属性注入引用类型值,name 属性的值是构造方法形参的值)--> <bean id="userServiceImpl" class="com.wlplove.service.UserServiceImpl"> <constructor-arg name="userDao" ref="userDao" /> </bean> 5.2.3、构造器注入的其他XML配置写法 5.2.3.1、type方式 在 constructor-arg 标签中使用 type 属性: <bean id="userDao" class="com.wlplove.dao.UserDao" /> <bean id="userServiceImpl" class="com.wlplove.service.UserServiceImpl"> <constructor-arg type="int" value="123" /> <constructor-arg type="java.lang.String" value="test" /> <constructor-arg type="com.wlplove.dao.UserDao" ref="userDao" /> </bean> type 方式解决了构造器注入时 name 属性绑定了形参名称从而造成强耦合的问题,如果一个 Bean 中某种类型(比如 int)的属性只有一个,那么可以用这种方式,反之,当相同类型的属性有很多个时,用这种方式就会给所有这种类型的属性都注入相同的值。 4.2.3.2、index索引方式 在 constructor-arg 标签中使用 index 属性: <!-- index索引方式,解决参数类型重复问题,使用索引进行参数匹配对应 --> <bean id="userDao" class="com.wlplove.dao.UserDao" /> <bean id="user" class="com.wlplove.dao.dto.User"> <constructor-arg index="0" value="20" /> <constructor-arg index="1" value="test" /> <constructor-arg index="2" ref="userDao" /> </bean> 5.3、基于XML文件的自动装配 所谓自动装配就是省略手动在 XML 中配置 Bean 依赖的步骤,而使 Spring 容器自动解析 Bean 之间的依赖关系,并将依赖的 Bean 注入到目标 Bean 中。需要注意的是,自动装配只针对于 Bean 中引用类型的依赖,简单类型的依赖无法被自动装配。 5.3.1、byType Spring 容器会根据属性的类型来自动装配。它会在容器中查找与需要注入的属性类型相同的 Bean,并将其注入到该属性中。 要使 Spring 容器按 Bean 类型自动装配,加入 autowire="byType": <bean id="bookService" class="com.wlplove.service.UserServiceImpl" autowire="byType" /> 使用 byType 这种方式,必须保证配置文件中所有 Bean 的 class 属性值是唯一的,否则就会报错 5.3.2、byName Spring 容器会根据属性名称来自动装配,在容器中查找与需要注入的属性名称相同的 Bean,并将其注入到该属性中。严格来说,此处的属性名称并非是指成员变量名称,而是指 set 方法名去掉 set 之后将首字母小写的名称,比如 User 类中 age 属性的 set 方法为 setAge1(),那么将 set 方法处理之后得到的属性名称为 age1,Spring 容器根据属性名称 age1 自动装配,而不是 age。 要使 Spring 容器按 Bean 名称自动装配,加入 autowire="byName": <bean id="bookService" class="com.wlplove.service.UserServiceImpl" autowire="byName" /> 5.3.3、constructor 基于构造函数的自动装配。Spring 容器会查找与构造函数中形参的数量与类型相同的 Bean,并通过构造函数注入。 <bean id="bookService" class="com.wlplove.service.UserServiceImpl" autowire="constructor" /> 5.4、基于注解的自动装配 除了 XML 配置,也可以使用 @Autowired 注解来实现自动装配: 构造器注入:将 @Autowired 注解标注在构造器上,Spring 容器根据构造器参数类型来注入依赖。 Setter方法注入:将 @Autowired 注解标注在 set 方法上,Spring 容器根据 set 方法的名称和参数类型来注入依赖。 字段注入:直接将 @Autowired 注解标注在字段上,Spring 容器根据字段类型来注入依赖。 六、集合的注入 接下来的例子以 setter 注入为例进行说明,构造器注入类似,将 <property></property> 标签修改为 <constructor-arg></constructor-arg> 即可。 6.1、注入数组 <!-- name 属性设置将数据注入哪一个数组 --> <property name="test_array"> <!-- 此处 array 与 list 可以混用 --> <array> <!-- 引用类型 --> <value>123</value> <value>456</value> <value>789</value> <!-- 引用类型 --> <!-- <ref bean="beanId"></ref> --> </array> </property> 6.2、注入 Set 对象 <property name="test_set"> <set> <value>set_qwe1</value> <value>set_asd2</value> <value>set_zxc3</value> <!-- 重复会自动过滤 --> <value>set_zxc3</value> </set> </property> 6.3、注入 List 对象 <property name="test_list"> <!-- 此处 array 与 list 可以混用 --> <list> <value>list_qwe1</value> <value>list_asd2</value> <value>list_zxc3</value> </list> </property> 6.4、注入 Map 类型数据 注入 Map 对象: <property name="test_map"> <map> <entry key="contry" value="China"></entry> <entry key="province" value="Gansu"></entry> <entry key="city" value="Lanzhou"></entry> </map> </property> 6.5、注入 property 类型数据 <property name="test_properties"> <props> <prop key="contry">China</prop> <prop key="province">Gansu</prop> s<prop key="city">Lanzhou</prop> </props> </property> <property> 标签表示 setter 方式注入,构造方式注入 <constructor-arg> 标签内部也可以写 <array>、<list>、<set>、<map>、<props> 标签 List 的底层也是通过数组实现的,所以 <list> 和 <array> 标签可以混用 若要在集合中添加引用类型,只需要把 <value> 标签改成 <ref> 标签,但这种方式用的比较少 七、Spring容器的核心操作 7.1、创建容器 通过类路径来加载配置文件的方式创建容器: ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); // 加载多个文件,也就是将多个XML文件的配置都加载到一个Spring容器中: ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext1.xml", "applicationContext2.xml"); 也可以通过文件路径来加载配置文件的方式创建容器: ApplicationContext ctx = new FileSystemXmlApplicationContext("E:\\applicationContext.xml"); // 加载多个文件,也就是将多个XML文件的配置都加载到一个Spring容器中: ApplicationContext ctx = new FileSystemXmlApplicationContext("E:\\applicationContext1.xml", "E:\\applicationContext2.xml"); 7.2、从Srping容器获取Bean 7.2.1、根据Bean名称/ID // 需要类型强制转换 BookDao bookDao = (BookDao) ctx.getBean("bookDao"); 7.2.2、根据Bean类型获取 // 参数是 类名.class BookDao bookDao = ctx.getBean(BookDao.class); 当按类型获取 Bean 时,必须保证该类型的 Bean 在 Spring 容器中只有一个,否则会抛出 NoUniqueBeanDefinitionException 异常。 7.2.3、根据Bean名称获取并指定类型 BookDao bookDao = ctx.getBean("bookDao", BookDao.class); 八、一图流总结 8.1、Bean: 8.2、依赖注入:
2021年11月05日
1,213 阅读
0 评论
4 点赞
2021-10-31
MySQL数据表中的auto_increment自增值属性及修改
目录: 0x01. 查看自增值 1、查看全局自增值 2、查看特定数据表的自增值 0x02. 自增值的取值问题 1、默认取值 2、建表时指定 3、直接指定 4、修改自增字段属性 环境说明: MySQL 5.7 、MySQL 8.0 长期以来,我的博客数据库中连续文章的主键编号一直都不是连续的,让我这个强迫症晚期患看着很不舒服。在忍受了这么长时间以后,趁着给博客换域名的时机,我把所有的文章编号全部改成了连续的,可算是舒服多了。 把改完主键编号的文章数据导入新数据库之后,就产生了一个新问题:现在新数据表的主键自增值还是旧数据表的主键自增值。比如说博客数据库的文章表中有80条数据,下次新创建文章的编号是以旧数据库的自增值202开始递增,生成的新文章编号是203,而不是81。如果要保持文章编号能连续的话,就只能每次发布完新博客之后再去改数据库中的编号,可谓是相当麻烦。 所以我便想着是否可以通过修改数据表里主键的 AUTO_INCREMENT 自动递增值来一步到位,查了一些资料之后,就有了这篇博客。 0x01. 查看自增值 一般来说,数据表中具有自增属性 AUTO_INCREMENT 的字段主要是数据表的主键或者具有唯一性的字段。 如果要查阅其递增值,有这么两种方式: 1、查看全局自增值 SHOW VARIABLES LIKE 'AUTO_INC%'; 这条命令的执行结果会返回两条数据: AUTO_INCREMENT_INCREMENT 表示自增的初始值,AUTO_INCREMENT_OFFSET 表示自增的步长,即每次的自增量。 修改自增初始值与自增量的命令: SET @@AUTO_INCREMENT_INCREMENT=新初始值; SET @@AUTO_INCREMENT_OFFSET=新步长; 注意:这个表示的是数据库全局的自增设置,因此修改以后只会影响到下次新增的带有 AUTO_INCREMENT 属性的列,其自增初始值与自增步长就是新设置的值,对当前已经带有 AUTO_INCREMENT 属性的列的自增初始值与自增步长不起作用。 2、查看特定数据表的自增值 要想查看某个数据表中自增字段的当前自增值,可用以下命令: SHOW TABLE STATUS FROM [数据库名] LIKE [表名]; FROM [数据库名] 与 LIKE [表名] 这两个子句是可选的。 FROM [数据库名] 表示指定查询所在的数据库;LIKE [表名] 指定该数据库下要查询的某个表,如果省略了 LIKE [表名] 子句,则表示查看该数据库下的所有表的信息。 另外,需要注意的是,表名要加引号。 比如查询 TEST 数据库下 test 表的信息: SHOW TABLE STATUS FROM TEST LIKE 'test'; 查询结果中有一个字段名为 “AUTO_INCREMENT”,表示的就是自增值,该表下一条记录的编号就是这个值。 0x02. 自增值的取值问题 1、默认取值 默认情况下,自增值从1开始,每增加一条新记录,自增值便会自增 1。 所以,对于具有 AUTO_INCREMENT 属性的列,不用特意设置列值,而是直接将 NULL 值插入到自增列中去,数据库会自动根据当前的自增值生成列值。 注意: 将 0 插入到自增列中的效果等同于插入 NULL 值; 当插入记录时,如果没有为自增列指明一个值,那么也等同于插入 NULL; 使用 INSERT 语句插入记录时,如果为自增列设置了一个值,那么会出现这样三种情况: 情况一,插入的值与已有的编号重复,则会出现报错 情况二,插入的值大于列的自增值,成功插入这条记录,并且会更新自增值为新值 情况三,插入的值小于列的自增值且与已有的编号不重复,则成功插入这条记录,但自增值不会更新,如果插入的值与已有的值重复,参考情况一 如果用 UPDATE 语句更新自增列,情况与 INSERT 语句相同。 2、建表时指定 我们也可在建表时使用 “AUTO_INCREMENT=自增值” 来指定一个自增的初始值,比如: CREATE TABLE TEST{ -- 建表语句 }AUTO_INCTEMENT=自增值; 3、直接指定 ALTER TABLE [表名] AUTO_INCREMENT=自增值; 如果执行完以后没有效果,那么可以再执行一次 commit 指令以提交更改,使其生效。 4、修改自增字段属性 ALTER TABLE [表名] MODIFY [字段名] [字段类型和约束条件], AUTO_INCREMENT=自增值; 同样的,如果执行完以后没有效果,再执行一次 commit 提交更改。 这个语句相当于直接修改自增字段的属性,包括其数据类型和约束条件。 另外,我在尝试中发现,使用 SQL 语句更改了自增值以后再执行 SHOW TABLE STATUS 语句来验证是否修改成功,本地的数据库显示自增值已经修改过来了。但是,服务器上的数据库自增值依然还是原来的值,可是,当我在重新插入一条记录时,新记录的自增值却是修改过后的值。这属实让我有点摸不着头脑,我也不太确定是不是 MySQL 版本不同的原因,也懒得再尝试了,所以把这种情况记录上来以供参考吧。
2021年10月31日
2,208 阅读
0 评论
0 点赞
2021-10-19
总结一下CSS3中的Flex布局语法
前排提示: 本篇博客篇幅较长,建议结合目录查看! 目录: 0x01. Flex 布局简介 如何应用 Flex 布局 0x02. 基本概念 0x03. 用于父元素的属性 3.1、flex-direction 属性取值 图示说明 CSS代码 3.2、flex-wrap 属性取值 图示说明 CSS代码 3.3、flex-flow 3.4、justify-content 属性取值 图示说明 CSS代码 3.5、align-items 属性取值 图示说明 CSS代码 3.6、align-content 属性取值 图示说明 CSS代码 0x04. 用于子元素的属性 4.1、flex-grow 属性取值 图示说明 CSS代码 4.2、flex-shrink 属性取值 图示说明 CSS代码 4.3、flex-basis 属性取值 CSS代码 4.4、flex 4.5、align-self 属性取值 图示说明 CSS代码 4.6、order 属性取值 0x05. 简单应用 Flex 布局有时候会用到,但是始终分不清楚其中的部分属性及其含义,所以用这篇博客专门总结一下 Flex 布局。 特别说明:博主初入门 Flex 布局看的是Flex 布局教程:语法篇 - 阮一峰的网络日志 (ruanyifeng.com)这篇教程,教程整体上条理清晰,讲得通俗易懂,但是不太方便快速查阅相关属性。因此本篇博客将以这篇教程为基础(所以不可避免地在文章结构与部分内容上可能会与教程有很大部分相似),以我自己的理解重新总结一遍 Flex 布局,以方便我自己查阅。如果您认为本篇博客讲的不够清楚,建议您参考教程原文。 另外,关于 Flex 布局中的属性效果演示,推荐看这个视频: {bilibili bvid="BV1oK4y1j7pa" page=""/} 0x01. Flex 布局简介 网页布局的传统解决方案,基于盒状模型,依赖 display 属性 + position 属性 + float 属性。它对于那些特殊布局非常不方便,比如,垂直水平居中就不容易实现。 2009年,W3C 提出了一种新的方案—— Flex 布局,可以简便、完整、响应式地实现各种页面布局。目前,它已经得到了所有浏览器的支持。 Flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。 简单来说,Flex 布局可以极大地改善对于父元素和多个子元素进行布局的难度。 如何应用 Flex 布局 刚开始接触到 Flex 布局的时候,那么多的属性及其含义倒不是首要问题,最大的问题是不知道如何去应用 Flex 布局。 其实给一个元素添加 Flex 布局很简单,只需要在 CSS 代码中设置其 display 属性为 flex 或者 inline-flex 即可。其中,对于Webkit 内核的浏览器,还必须加上-webkit前缀。 对于div、p、form、ul、ol等这些块状元素,使用 Flex 布局的方式为(以 div 为例): div{ display:flex; display:-webkit-flex } 对于诸如 span 等行内元素来说需要将属性值更换为 inline-flex: span{ display:inline-flex; display:-webkit-inline-flex; } 注意:设置 Flex 布局以后,子元素的 float、clear 和 vertical-align 属性将失效。 0x02. 基本概念 将采用了 Flex 布局的元素称为 Flex 容器(flex container)。它的所有子元素将自动成为容器成员,成为 Flex 项目(flex item)。 在 Flex 容器中,默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)(不知道为什么会起这么奇怪的名字)。 其中,主轴的开始位置叫做 main start,结束位置叫做 main end;而交叉轴的开始位置叫做 cross start,结束位置叫做 cross end。 子元素默认沿主轴排列,单个子元素所占的主轴空间叫做 main size,占据的交叉轴空间为 cross size。 以上就是在 Flex 布局中涉及到的一些基本概念。 除了基本概念之外,还有许多 Flex 布局会用到的属性,根据这些属性的使用位置可以简单将其分为两类,分别是应用在父元素(容器)上的属性和应用在子元素(项目)上的属性。下面分别对其进行简单的介绍与解释。 0x03. 用于父元素的属性 3.1、flex-direction flex-direction属性决定主轴的方向,表现就是 Flex 容器中子元素的排列方向(比如说横向或纵向)。 属性取值 默认值为 row。 属性名 含义 row(默认值) 主轴为水平方向,起点在左端 row-severse 主轴为水平方向,起点在右端 column 主轴为垂直方向,起点在上边 column-reverse 主轴为垂直方向,起点在下边 图示说明 CSS代码 .box { flex-direction: row | row-reverse | column | column-reverse; } 3.2、flex-wrap 默认情况下,子元素都排在一条轴线上。 当子元素多到一条轴线排列不下的时候,用 flex-wrap 就可以定义这些子元素换行的形式,比如顺序、倒序之类的。 属性取值 默认取值为 nowrap,即不换行。 属性名 作用 nowrap(默认) 不换行 wrap 换行,第一行在上方 wrap-reverse 换行,第一行在下方 图示说明 CSS代码 .box { flex-wrap: nowrap | wrap | wrap-reverse; } 3.3、flex-flow flex-flow 属性是 flex-direction 和 flex-wrap 的缩写形式。 默认值为 row nowrap。 3.4、justify-content justify-content 属性定义了子元素在主轴上的对齐方式(比如靠左/右/上/下、居中等等)。 注意:这个属性与 flex-direction 有区别,不能混淆。 属性取值 默认值为 flex-start。 属性名 作用 flex-start(默认) 左对齐 flex-end 右对齐 center 居中 space-between 两端对齐,子元素之间的间隔相等 space-around 每个子元素两侧的间距相等 space-evenly 子元素之间的间隔和子元素与边框的间隔相等(兼容性较差) 图示说明 CSS代码 .box { justify-content: flex-start | flex-end | center | space-between | space-around; } 3.5、align-items align-items 属性定义子元素在交叉轴上的对齐方式(与 justify-content 属性类似)。 属性取值 默认值为 stretch。 属性名 作用 stretch(默认) 表示如果子元素未设置高度或设为auto,将占满整个容器的高度 flex-start 从交叉轴的起点对齐 flex-end 从交叉轴的终点对齐 center 从交叉轴的中点对齐 baseline 按照子元素的第一行文字的基线对齐 图示说明 CSS代码 .box { align-items: flex-start | flex-end | center | baseline | stretch; } 3.6、align-content align-content 属性定义了多根轴线的对齐方式。如果子元素只有一根轴线,则属性不起作用。 属性取值 默认值为 stretch。 属性名 作用 flex-start 沿交叉轴的起点对齐 flex-end 沿交叉轴的终点对齐 center 沿交叉轴的中点对齐 space-between 与交叉轴两端对齐,轴线之间的间隔平均分布 space-around 每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍 stretch(默认值) 轴线占满整个交叉轴 图示说明 CSS代码 .box { align-content: flex-start | flex-end | center | space-between | space-around | stretch; } 0x04. 用于子元素的属性 4.1、flex-grow 元素布局时经常会出现这样的情况,当所有子元素水平排列时的宽度之和(或者纵向排列时的高度之和)小于父元素的宽度(高度)时,则当前父元素在这个方向上就会出现剩余空间。那么此时就可以用 flex-grow 属性来分配这些剩余空间,以使子元素完全填充父元素。 属性取值 flex-grow 属性的值是一个数字,没有单位。 默认值为0,表示如果存在剩余空间,也不会放大子元素的宽度(或高度)。 当给子元素的 flex-grow 属性值设置为一样时,表示平均分配这个方向上的宽度(高度),可以利用这点来给元素做等宽布局。 如果一个子元素的 flex-grow 属性为2,其他子元素都为1,则前者占据的剩余空间将比其他项多一倍。 注意:当子元素的宽度/高度(width/height)属性与 flex-grow 同时存在时,元素最终的宽度/高度将由 flex-grow 属性来决定。 图示说明 CSS代码 .item { flex-grow: <number>; /* default 0 */ } 4.2、flex-shrink 这个属性的含义与 flex-grow 相反,当剩余空间较小不足以容纳所有子元素时,就可用这个属性指定某个子元素的缩小比例。 属性取值 类似 flex-grow,flex-shrink 属性的值也是一个数字。该属性默认值为1,即如果空间不足,该子元素将缩小。 如果所有子元素的 flex-shrink 属性都为1,当空间不足时,这些子元素都将等比例缩小。 如果一个子元素的 flex-shrink 属性为0,其他子元素属性为1,则空间不足时,前者不缩小。 负值对该属性无效。 图示说明 CSS代码 .item { flex-shrink: <number>; /* default 1 */ } 4.3、flex-basis flex-basis属性定义了在分配多余空间之前,子元素占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。 属性取值 默认值为 auto,即子元素本来的大小。 flex-basis 属性值可以设置成与 width 或者 height 属性一样的值,则子元素将占据固定空间。 CSS代码 .item { flex-basis: <length> | auto; /* default auto */ } 4.4、flex 类似于前面的 flex-flow 属性,flex 属性是 flex-grow、flex-shrink 和 flex-basis 这几个属性的缩写形式。后两个属性(flex-shrink 和 flex-basis)可选。 默认值为“0 1 auto”。 4.5、align-self align-self 属性允许某个子元素有与其他子元素有不一样的对齐方式,设置了这个属性之后,将会覆盖父元素的 align-items 属性。 默认值为 auto,表示继承父元素的 align-items 属性,如果没有父元素,则等同于 strech。 属性取值 该属性的取值除了 auto ,其余的与 align-self 属性的取值相同。 属性名 作用 auto(默认) 继承父元素的 align-items 属性 flex-start 沿交叉轴的起点对齐 flex-end 沿交叉轴的终点对齐 center 沿交叉轴的中点对齐 baseline 按照子元素的第一行文字的基线对齐 stretch 如果子元素未设置高度或设为auto,将占满整个容器的高度 图示说明 CSS代码 .item { align-self: auto | flex-start | flex-end | center | baseline | stretch; } 4.6、order order 属性可以很方便地定义子元素的排列顺序,而不用去调整 HTML 代码中元素的代码顺序。 属性取值 默认值为0。 属性取值为数字,数字数值越小,则子元素排列越靠前。 0x05. 简单应用 其中最直观的应用就是将一个元素进行垂直水平方向的居中,且不管页面变化,依然能够生效。以 div 为例进行说明: <html> <head> <style> body{ background-color:#ccc; display:flex; justify-content:center; align-items:center; } div{ border:3px solid #000; background-image: linear-gradient(to right, #a18cd1, #fbc2eb); border-radius: 10px; width: 20%; height: 40%; } </style> </head> <body> <div></div> </body> </html> 预览效果: 在使用 Flex 布局方式进行垂直水平方向的居中布局时,只需要给父元素添加 Flex 布局方式,然后将 justifu-content 与 align-items属性值都设为 center 即可,不仅设置起来简单,还能保持良好的兼容性。 参考资料: Flex 布局教程:语法篇 - 阮一峰的网络日志 (ruanyifeng.com) Flex 布局教程:实例篇 - 阮一峰的网络日志 (ruanyifeng.com) Bilibili视频链接:20分钟掌握CSS Flex布局 - bilibili 文中图片出自:Flex 布局教程:语法篇 - 阮一峰的网络日志 (ruanyifeng.com)
2021年10月19日
1,683 阅读
0 评论
2 点赞
2021-09-30
【踩坑实录】mybatis项目报错:Establishing SSL connection without...property is set to false
环境说明: 系统:Win10专业版 mysql 5.7 问题再现 操作数据库时,警告信息如下: WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification. 以上警告信息翻译一下就是: 警告:不建议在没有服务器身份验证的情况下建立 SSL 连接。 根据MySQL 5.5.45+、5.6.26+ 和 5.7.6+ 要求,如果未设置显式选项,则必须默认建立 SSL 连接。 为了符合不使用 SSL 的现有应用程序,verifyServerCertificate 属性设置为“false”。您需要通过设置 useSSL=false 来显式禁用 SSL,或者设置 useSSL=true 并为服务器证书验证提供信任库。 解决方法 最省事的方法是修改数据库连接信息,在链接之后加上“useSSL=false”,直接禁用SSL连接方式。 原来链接为: jdbc:mysql://localhost:3306/mybatis?setUnicode=true&characterEncoding=utf8 加上参数之后修改为: jdbc:mysql://localhost:3306/mybatis?setUnicode=true&characterEncoding=utf8&useSSL=false 如果将参数设置为“useSSL=true”,在IDEA数据库连接界面设置SSL证书,也可以消除警告:
2021年09月30日
1,926 阅读
0 评论
0 点赞
2021-09-14
目前最流行的版本控制软件:Git的基本使用
前排提示: 本篇博客篇幅较长,建议结合目录查看! 目录: 写在前面 1、关于版本控制系统 定义 版本控制的必要性: 常见的版本控制系统 2、Git与Github 0x01.安装Git 0x02.Github中的一些基本概念 Repository Issue Star Fork Pull Request Watch Wiki Gist 0x03.添加SSH key 0x04.克隆仓库 0x05.初始化仓库 0x06.提交修改 0x07.分支操作 查看分支 建立新分支 切换分支 建立并切换到新分支 推送本地分支到远程仓库 合并分支 删除分支 重命名分支 0x08.标签操作 附注标签 轻量标签 切换标签 推送标签 删除标签 查看所有标签 给提交打标签 写在前面 1、关于版本控制系统 定义 版本控制(Version control)是维护项目的标准作法,能追踪项目从诞生一直到定案的过程。此外,版本控制也是一种软件工程技巧,借此能在软件开发的过程中,确保由不同人所编辑的同一程序文件都得到同步,记录项目内各个模块的改动历程,并为每次改动都编上序号。 一种简单的版本控制形式如下:工程的初代版本为“1.0”,当做了第一次改变后,版本等级改为“1.1”,以此类推。因此,版本控制能提供给开发者将项目恢复到之前任一状态的选择权,这种选择权在设计过程进入死胡同时特别重要。 版本控制的必要性: 常会利用版本控制来追踪维护源代码、文件以及配置文件等的改动,并且提供控制这些改动控制权的程序; 有时候,一个程序同时存有两个以上的版本,例如:在一个稳定版本中程序错误已经被修正、但没有加入新功能;在另一个开发版本则有新的功能正在开发、也有新的错误待解决,这使得同时间需要不同的版本; 此外,为了找出只存在于某一特定版本中(由于修正了某些问题、或新加功能所导致)的程序错误,或找出程序错误出现的版本,开发者也需要比对不同版本的代码以找出问题的位置。 常见的版本控制系统 集中式版本控制系统:由一台或多台主计算机组成中心服务器,所有业务单元和项目版本库都集中存储在这个中心服务器上,开发时,要先从中央服务器取得项目最新的版本,一次开发完毕之后,再将工作量推送给中央服务器。就像是一个图书馆,如果要改一本书的内容,则需要把书先从图书馆借出来,然后修改,改完之后再放回图书馆。 因此,集中式版本控制系统最的大缺点就是中央服务器出了问题,所有人都没法工作了。 常见的集中式版本控制系统有SVN、CVS等。 分布式版本控制系统:分布式版本系统没有绝对的中央服务器,每个人的电脑上都是一个完整的版本库,多个人进行协同工作时,只需将自己的修改与其他人的修改进行交换即可 和集中式版本控制系统相比,分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,其中一个人的电脑坏了不要紧,从其他人那里复制一个就可以了。 Git就是常见的分布式版本控制系统之一,也是目前最流行的版本控制系统。 2、Git与Github 准确地说,Git与Github根本不是同一个概念。 Git是指由Linus(就是那位二十多年前徒手撸出Linux内核的大佬)编写的分布式版本控制系统,于2005年以GPL发布。最初目的是为了更好地管理Linux内核开发。 自2002年以来,Linus一直使用BitKeeper作为Linux内核主要的版本控制系统以维护代码。在Linux社区中,主张应该使用开放源代码的软件来作为Linux内核的版本控制系统。Linus曾考虑过采用现成软件作为版本控制系统(例如Monotone),但这些软件都存在一些问题,特别是性能不佳。 2005年,Linux社区中的安德鲁·垂鸠写了一个可以连接BitKeeper的存储库的简单程序,BitKeeper著作权拥有者拉里·麦沃伊便认为安德鲁·垂鸠对BitKeeper内部使用的协议进行了逆向工程,决定收回无偿使用BitKeeper的许可。Linux内核开发团队与BitMover公司进行磋商无果后,Linus决定自行开发版本控制系统以替代BitKeeper,在十天的时间编写出git第一个版本。于是,世界上最流行的版本控制系统就这么戏剧式地诞生了。 而GitHub是通过Git进行版本控制的软件源代码托管服务平台,由GitHub公司(曾称Logical Awesome)的开发者Chris Wanstrath、P. J. Hyett和Thomas Preston-Werner使用Ruby on Rails编写而成,于2007年10月1日开始开发。beta版本开始上线于2008年2月,4月份正式上线。这是他们的logo,名字叫Octocat: 截止到2020年1月,GitHub已经有超过4000万注册用户和1.9亿代码库(包括至少2800万开源代码库),事实上已经成为了世界上最大的代码存放网站和开源社区,国内很多人戏称为“全球最大同性交友网站”。 2018年6月4日晚,微软宣布以75亿美元的股票收购GitHub。 Github服务器在国外,处于半被墙的状态,有时正常访问,有时又打不开。与之类似的代码托管平台Gitee可以看做是国内版的Github,缺点是开源项目不如Github丰富,当然,由于在访问时速度更快,更适合国内用户托管代码。而且,部分开源项目是同时托管在这两个平台上的,所以碰到无法打开的Github项目时,在Gitee上找找也许会有惊喜。 0x01.安装Git Git在全平台均可使用。 Git官网:Git (git-scm.com) 官方中文文档:Git - Book (git-scm.com) Windows系统Git安装包下载链接:Git - Downloads Linux系统安装Git:Git - Download for Linux and Unix Mac系统安装Git:Git - Download for macOS 安装完成之后在控制台中输入git,如果出现如下输出说明安装成功: 前面提到过,Git只是一个分布式版本管理软件,每个人的计算机都是一份完整的版本库,对这份版本库进行修改之后,将每个人的修改进行合并。但是如果不在同一个内网中,合并修改就会变得困难。此时也需要一个中央服务器来辅助进行代码的合并。这也就是Github、Gitee、Gitlab等平台最基本的作用。 因此,我们还需要注册一个Github/Gitee账号,将我们的代码托管到平台上面(从某种角度上将它看成一个专门存放代码的云盘也未尝不可)。Github注册账号及用户界面介绍可以参考这篇文章:从0开始学习 GitHub 系列之「加入 GitHub」 (qq.com),本篇博客不再介绍。 0x02.Github中的一些基本概念 Repository 仓库,即项目,要在GitHub上开源一个项目,那就必须要新建一个Repository。 Issue 问题的意思,举个例子,比如开源的项目,别人发现项目中有bug,或者哪些地方做的不够好,他就可以提个Issue,即问题,提的问题多了,也就是 Issues ,然后开发者看到了这些问题就可以去逐个修复,修复ok了就可以一个个的Close掉。 Star 就是给项目点赞,这个star的含金量还是挺高的。 Fork 这个可以翻译成分叉,你想在某个开源项目的基础上做些改进,然后应用到自己的项目中,这个时候就可以Fork这个项目,与此同时你的GitHub主页上就多了一个项目,只不过这个项目是基于这个开源项目(本质上是在原有项目的基础上新建了一个分支)。而你就可以随心所欲的去改进这个项目了,丝毫不会影响原有项目的代码与结构。 Pull Request 发起请求,这个其实是基于Fork的,还是上面那个例子,如果你在项目基础上做了改进,就可以把自己的改进合并到原有项目里,这个时候你就可以发起一个Pull Request(简称PR),原有项目开发者会收到这个请求,这个时候他会review代码,并且测试觉得OK了,就会接受PR,这个时候新的改进会被合并进原有项目。 Watch 可以理解为观察,如果Watch了某个项目,以后如果这个项目有更新,都会收到关于这个项目的通知提醒。 Wiki 一般来说,项目的主页有README文件基本就够了,但是有些时候项目的一些用法很复杂,就需要有详细的说明文档给使用者。这个时候就可以用Wiki,使用markdown语法即可进行编写。 Gist 如果没有项目可以开源,只是单纯的想分享一些代码片段,那这个时候Gist就派上用场了。 0x03.添加SSH key 当我们对代码进行提交时,Github/Gitee要怎么知道是我们提交的代码,而不是别人提交的呢,所以就需要进行授权来确认我们的身份。 Github和Gitee服务器可以选择使用SSH公钥或GPG公钥来进行授权,这里采用SSH授权方式,提交代码之前需要先添加SSH key配置。大概步骤就是先在本地生成SSH key,然后将本地生成的SSH key添加到Github或者Gitee上。 SSH(Secure Shell)是一种建立在应用层基础上的安全协议,一般用于远程登录会话和其他网络服务。由于在传输过程中对数据进行了加密和压缩,因此可以有效防止远程管理过程中的“中间人攻击”,传输速度也会更快,还能够防止”DNS欺骗“和”IP欺骗“等。 生成SSH密钥: ssh-keygen -t rsa 这句命令的意思是用RSA算法生成密钥(windows系统最好在Git Bash下执行,cmd终端可能并没有安装ssh),执行后出来三次提示均按回车,命令执行完会生成id_rsa(密钥)和id_rsa.pub(公钥)这两个文件。Linux/Mac系统在~/.ssh下,windows系统在C:\Users\用户名\.ssh(用户名是自己电脑的用户名)下,需要设置显示隐藏文件选项才能看到。 将id_rsa.pub用文本编辑器打开,复制里面的内容。 添加公钥到Github/Gitee: 进入Github/Gitee的设置界面,在左侧选项列表找到SSH keys选项 将刚才复制的公钥粘贴上去,公钥标题可写可不写,然后保存,这样就完成了公钥的添加。 0x04.克隆仓库 说来惭愧,这是我接触到Github之后很长时间内最常用的操作(因为就只会这一个操作)。命令很简单: git clone [仓库链接] 这个命令的作用就是从Github上下载别人仓库的项目文件,可能是从clone直接音译过来的原因,这个操作一般都称克隆,而不叫下载。 克隆操作只需要有远程仓库链接即可,不需要Github账户也可以进行。克隆完之后项目文件的位置就是执行命令时所处的文件夹。 远程仓库链接在项目主页就可以找到: 0x05.初始化仓库 所谓初始化本地仓库,个人理解就是向本地的项目根目录文件夹中加入一些Git配置文件,使其可以被Git识别以进行版本控制,因为项目文件夹是不能直接进行版本控制的。 初始化本地仓库命令很简单,进入本地项目文件夹(或者用空文件夹),在该目录下执行: git init 也可以在命令后面加入文件夹路径,将指定文件夹初始化成本地仓库: git init [项目文件夹名路径] 项目初始化成功会有Initialized empty Git repository in xxxxxxx的提示,原项目文件夹中多出一个.git隐藏文件夹。此时初始化的本地项目还没有关联到远程仓库。 当然,有本地仓库还不行,我们本意是要把本地仓库推送到远程仓库,因此,还需要在Github/Gitee上建一个远程仓库。点击网站右上角加号,找到“New Repository(新建仓库)” 上图最后三项是用来初始化远程仓库的,如果这三项都不选就创建了仓库,就会提示用命令行来手动初始化远程仓库(所以建议对命令行不感冒的同学直接使用自带的初始化操作)。 来记录一下用命令行手动初始化远程仓库的步骤: 先在本地初始化好的Git项目中新建一个README.md项目说明文件(也可以是别的文件名) 在项目目录下执行命令与远程仓库进行关联: git remote add origin [远程仓库链接] 依次执行以下命令向暂存区加入修改文件,并编辑提交信息 git add README.md # 引号中就是本次提交信息,可修改 git commit -m "first commit" 向远程仓库推送本地仓库文件: Gitee只执行这条命令即可推送: git push -u origin master 从2020年10月开始,Github的默认分支从master变成了main,因此还需要将本地默认主分支重命名为main才能推送成功: git branch -M main git push -u origin main 如果不重命名主分支,就会出现“error: src refspec main does not match any,error: failed to push some refs to ..”的错误。 上述命令执行完之后,再刷新远程仓库界面,就进入了初始化好的远程仓库: 对于都已经初始化过的本地空仓库与远程仓库,使其建立关联可以这样做: # 先关联远程仓库 git remote add origin [仓库远程链接] # 再将远程仓库内容拉取到本地 git pull origin master 0x06.提交修改 所谓修改,就是相对于上次提交之后项目发生的改变(项目文件的增、删、改)。 其中要涉及到push和pull这两个互为相反的概念: Push:直译就是“推”的意思,这个操作可以把本地代码推到远程仓库,这样本地仓库跟远程仓库就可以保持同步了。 Pull:直译为“拉”的意思,如果别人提交代码到远程仓库,这个时候本地仓库代码与远程仓库代码并不一致,所以需要把远程仓库的最新代码拉下来,以保证两端代码的同步。 同时,提交代码前最好设置一下提交者的名字与邮箱,方便在commit记录里显示: git config —global user.name "名字" git config —global user.email "邮箱" 通常一次完整的提交过程如下: 将修改过的文件加入暂存区: git add [修改的文件或者目录] # .表示此目录下所有文件,一次提交的文件较多时,可以使用此命令 git add . 确认提交暂存区中的文件: # -m表示附加提交信息,后面的内容是关于提交的信息说明 git commit -m "提交信息" git add是先把改动添加到一个“暂存区”,可以理解成是一个缓存区域,临时保存改动,而git commit才是最后真正的提交。这样做的好处是防止误提交。 最后将代码推送到远程仓库指定分支,即可完成一次代码提(其中注意,最后提交时Gitee与Github的分支名有所不同): # 推送代码到指定分支 git push origin [分支名] # Github默认分支是main,用以下命令: git push origin main # Gitee默认分支是master,用以下命令: git push origin master 这里的origin是给远程仓库起的名字,当然名字并不唯一,可以是其他名字,只是因为习惯,一般都起名为origin。 一般在多人协作时,为了不产生代码冲突,提交代码前最好进行一次Pull操作: git pull origin [分支名] 查看git仓库当前状态,比如当前所在分支、被修改过的文件、未提交的文件等等: git status 查看提交时产生的所有commit记录: git log 0x07.分支操作 branch即分支的意思,分支的概念在团队协作的时候很重要,假设两个人都在做同一 个项目,这个时候分支就是保证两人能协同合作的最大利器了。举个例子,A, B两人在做同一个项目不同的模块,这个时候A新建了一个分支叫a,B新建了一个分支叫b,这样 A、B做的所有代码改动都在各自的分支上,互不影响,等到都把各自的模块做完 了,最后再统一把分支合并到master主分支。 在本地执行git init命令初始化仓库时默认生成一个主分支master。 而远程仓库的情况就有所不同了,曾经Github远程仓库的默认主分支也是master,但是去年(2020)10月份之后Github将默认主分支名称从master改成了main(据说是因为master这个词意为奴隶的主人,含有种族歧视意味),这也是在前面手动初始化Github仓库时要将主分支名重命名为main的原因。 而Gitee的主分支名称依然是master。 查看分支 查看本地分支列表: git branch 查看远程分支列表: git branch -r 建立新分支 git branch [分支名] 需要注意的是,新创建的分支的内容与当前所在的分支的内容相同,即新分支是基于当前所在的分支而创建的。 当我们建立了新分支以后,默认不会切换到新分支上,当前做出的任何更改还是基于当前所在的分支,所以需要切换分支。 切换分支 git checkout [分支名] # 切换到新分支之后手动拉取最新内容 git pull origin [分支名] 此时进行的改动就是在新分支下面了。当然,也有办法一步到位,加入-b参数即可。 建立并切换到新分支 git checkout -b [分支名] 推送本地分支到远程仓库 在本地建完新分支之后,就可以将本地新分支推送到远程仓库了,以保证两端同步 git push origin [新分支名] 如果本地推送到远程的分支想取另一个名字,那么可以用这条命令: git push origin [本地分支名]:[远程新分支名] 但是强烈不建议这样,这会导致管理混乱,建议本地分支跟远程分支名要保持 一致。 合并分支 当团队中不同成员都完成了开发之后,就可以将改动都合并到一块了。 # 首先切换到要合并到的分支上来,比如master(main)分支或是指定分支 git checkout [分支名]/main/master # 进行合并,将指定分支合并到当前所在的分支(即上一步切换到的分支)上来 git merge [指定分支] 在没有冲突的情况下,代码就可以合并完成了。合并完记得把新代码push到远程仓库。 删除分支 分支建错或者该分支的代码已经顺利合并到其他分支的时候,就可以删除分支了: git branch -d [分支名] 有些时候可能会删除失败,比如该分支的代码还没有合并到master或者其他分支,执行删除分支操作就会失败,Git会提示这个分支上还有未合并的代码,但是也可以强制删除分支: git branch -D [分支名] 以上仅仅为删除本地分支,若要删除远程分支可以可以运行带有 --delete 选项的 git push 命令: git push origin --delete [远程分支名] 重命名分支 将A分支重命名为B分支: git branch -m A B 类似于删除分支,无法重命名时,也可以强制重命名: git branch -M A B 如果是重命名远程分支,推荐的做法是: 删除远程待修改分支 push本地新分支名到远程 0x08.标签操作 开发的时候经常有版本的概念,比如v1.0、v1.1之类的,不同的版本肯定对应不同的代码,所以给代码打上标签,标签名可以是版本号或者其它标记。 Git 支持两种标签:附注标签(annotated)与轻量标签(lightweight)。 附注标签 附注标签是存储在Git数据库中的一个完整对象, 它们是可以被校验的,其中包含打标签者的名字、邮件地址、日期时间, 此外还有一个标签信息,并且可以使用GNU Privacy Guard(GPG)签名并验证。 通常建议创建附注标签,这样就可以拥有以上所有信息 添加附注标签信息用这条命令: git tag -a [标签名] -m "标签信息" -m参数为可选的,表示指定一条存储在标签中的信息。如果省略-m参数,那么Git会自动打开编辑器,让我们写一句标签信息,就像给提交写注解一样。 利用git show命令可以查看标签信息与对应的提交信息: git show [标签名] 输出会显示打标签者的信息、打标签的日期时间、附注信息与具体的提交信息。 轻量标签 如果只是想用一个临时的标签, 或者因为某些原因不想要保存这些信息,那么就可以用轻量标签。 轻量标签很像一个不会改变的分支——它只是某个特定提交的引用。本质上是将提交校验和存储到一个文件中——没有保存任何其他信息。 创建轻量标签,不需要使用 -a、-s 或 -m 选项,只需要提供标签名: git tag [标签名] 同样的,利用git show命令查看标签信息与对应的提交信息,输出只会显示出提交信息,不会看到额外的标签信息。 切换标签 当要切换到某个tag时,命令与切换分支类似: git checkout [标签名]; 推送标签 同样的,向远程仓库推送单个标签的命令与推送分支也是类似的: git push origin [标签名] 如果一次推送多个标签,可以使用带有--tags的git push命令: git push origin --tags 这条命令会将所有不在远程仓库服务器上的标签全部推送到远程仓库。 删除标签 删除本地标签: git tag -d [标签名] 上述命令并不会从远程仓库中移除这个标签,从远程仓库移除标签有两种办法: git push <remote> :[标签名称] 这种操作的含义是,将冒号前面的空值推送到远程标签名,从而实现删除的效果。 第二种方式相对来说更直观: git push origin --delete [标签名] 查看所有标签 执行git tag命令,就可以列出所有标签: git tag 默认是以字母顺序排列标签。 当然,可带上可选的 -l 选项或者 --list选项,以匹配特定标签名: git tag -l "通配符" # 或者 git tag --list "通配符" 例如,只查阅v2.*版本的标签名: git tag -l "v2.*" 给提交打标签 假设在过去某一个时刻提交了项目更改,后期才想起来忘记给项目打标签了,那么也可以在之后补上标签: git tag -a [标签名] [校验和] 与创建标签命令不同,需要在标签名之后添加一个校验和选项(也可以是部分校验和)。 通过以下命令可以查看每一次提交的校验和与对应的提交信息: git log --pretty=oneline 参考资料: 微信公众号 - stormzhang:从0开始学习Github系列文章 Git 教程 | 菜鸟教程 (runoob.com) Git - Book (git-scm.com) 版本控制 - 维基百科,自由的百科全书 (wikipedia.org) git - 维基百科,自由的百科全书 (wikipedia.org) GitHub - 维基百科,自由的百科全书 (wikipedia.org)
2021年09月14日
1,205 阅读
0 评论
0 点赞
1
2
3
4
...
10