度小滿面試題20190923

1. 一面

1. SpringBoot 註解以及自動配置(生效條件)

@SpringBootApplicationhtml

@SpringBootConfigurationjava

@EnableAutoConfigurationmysql

@ComponentScanreact

@Configurationlinux

1、@SpringBootApplication
  @SpringBootApplication註解是Spring Boot的核心註解,它實際上是一個組合註解.
  
  /** @SpringBootApplication註解的源碼

@Target(ElementType.TYPE)註解的做用目標
@Retention(RetentionPolicy.RUNTIME) 註解的保留位置
@Documented 註解將被包含在javadoc中
@Inherited 子類能夠繼承父類中的該註解
@SpringBootConfiguration 修飾Spring Boot的配置
@EnableAutoConfiguration 開啓自動配置
@ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class))ios

該註解會自動掃描包路徑下面的全部@Controller、@Service、@Repository、@Component 的類,不配置包路徑的話,在Spring Boot中默認掃描@SpringBootApplication所在類的同級目錄以及子目錄下的相關注解。c++

**/程序員

  用在 Spring Boot 主類上,標識這是一個 Spring Boot 應用,用來開啓 Spring Boot 的各項能力。
  這個註解就是 @SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan 這三個註解的組合,也能夠用這三個註解來代替 @SpringBootApplication註解。

2、@EnableAutoConfiguration

  容許 Spring Boot 自動配置註解,開啓這個註解以後,Spring Boot 就能根據當前類路徑下的包或者類來配置 Spring Bean。
  如:當前類路徑下有 Mybatis 這個 JAR 包,MybatisAutoConfiguration 註解就能根據相關參數來配置 Mybatis 的各個 Spring Bean。

3、@Configuration

  這是 Spring 3.0 添加的一個註解,用來代替 applicationContext.xml 配置文件,全部這個配置文件裏面能作到的事情均可以經過這個註解所在類來進行註冊。

4、@SpringBootConfiguration

  這個註解就是 @Configuration 註解的變體,只是用來修飾是 Spring Boot 配置而已,或者可利於 Spring Boot 後續的擴展。

5、@ComponentScan

  這是 Spring 3.1 添加的一個註解,用來代替配置文件中的 component-scan 配置,開啓組件掃描,即自動掃描包路徑下的 @Component 註解進行註冊 bean 實例到 context 中。6、@Conditional

  這是 Spring 4.0 添加的新註解,用來標識一個 Spring Bean 或者 Configuration 配置文件,當知足指定的條件纔開啓配置7、@ConditionalOnBean

  組合 @Conditional 註解,當容器中有指定的 Bean 纔開啓配置。

8、@ConditionalOnMissingBean

  組合 @Conditional 註解,和 @ConditionalOnBean 註解相反,當容器中沒有指定的 Bean 纔開啓配置。

9、@ConditionalOnClass

  組合 @Conditional 註解,當容器中有指定的 Class 纔開啓配置。

10、@ConditionalOnMissingClass

  組合 @Conditional 註解,和 @ConditionalOnMissingClass 註解相反,當容器中沒有指定的 Class 纔開啓配置。

11、@ConditionalOnWebApplication

  組合 @Conditional 註解,當前項目類型是 WEB 項目纔開啓配置。
  enum Type {
      /**
       * Any web application will match.
       */
      ANY,
      /**
       * Only servlet-based web application will match.
       */
      SERVLET,
      /**
       * Only reactive-based web application will match.
       */
      REACTIVE
  }
12、@ConditionalOnNotWebApplication

  組合 @Conditional 註解,和 @ConditionalOnWebApplication 註解相反,當前項目類型不是 WEB 項目纔開啓配置。

13、@ConditionalOnProperty

  組合 @Conditional 註解,當指定的屬性有指定的值時纔開啓配置。

14、@ConditionalOnExpression

  組合 @Conditional 註解,當 SpEL 表達式爲 true 時纔開啓配置。

15、@ConditionalOnJava

  組合 @Conditional 註解,當運行的 Java JVM 在指定的版本範圍時纔開啓配置。

16、@ConditionalOnResource

  組合 @Conditional 註解,當類路徑下有指定的資源纔開啓配置。

17、@ConditionalOnJndi

  組合 @Conditional 註解,當指定的 JNDI 存在時纔開啓配置。

18、@ConditionalOnCloudPlatform

  組合 @Conditional 註解,當指定的雲平臺激活時纔開啓配置。

19、@ConditionalOnSingleCandidate

  組合 @Conditional 註解,當指定的 class 在容器中只有一個 Bean,或者同時有多個但爲首選時纔開啓配置。

20、@ConfigurationProperties

  用來加載額外的配置(如 .properties 文件),可用在 @Configuration 註解類,或者 @Bean註解方法上面。

21、@EnableConfigurationProperties

  通常要配合 @ConfigurationProperties 註解使用,用來開啓對 @ConfigurationProperties註解配置 Bean 的支持。

22、@AutoConfigureAfter

  用在自動配置類上面,表示該自動配置類須要在另外指定的自動配置類配置完以後。

  如 Mybatis 的自動配置類,須要在數據源自動配置類以後。

  @AutoConfigureAfter(DataSourceAutoConfiguration.class)
  public class MybatisAutoConfiguration {}
23、@AutoConfigureBefore   這個和 @AutoConfigureAfter 註解使用相反,表示該自動配置類須要在另外指定的自動配置類配置以前。 24、@Import   這是 Spring 3.0 添加的新註解,用來導入一個或者多個 @Configuration 註解修飾的類,這在 Spring Boot 裏面應用不少。 25、@ImportResource   這是 Spring 3.0 添加的新註解,用來導入一個或者多個 Spring 配置文件,這對 Spring Boot 兼容老項目很是有用,由於有些配置沒法經過 Java Config 的形式來配置就只能用這個註解來導入。

 

2. SpringMVC過濾器&攔截器

(1)過濾器(Filter):它依賴於servlet容器。
  在實現上,基於函數回調
  它能夠對幾乎全部請求進行過濾,可是缺點是一個過濾器實例只能在容器初始化時調用一次。
  使用過濾器的目的,是用來作一些過濾操做,獲取咱們想要獲取的數據,
  好比:在Javaweb中,對傳入的request、response提早過濾掉一些信息,或者提早設置一些參數,而後再傳入servlet或者Controller進行業務邏輯操做。
  一般用的場景是:在過濾器中修改字符編碼(CharacterEncodingFilter)、在過濾器中修改HttpServletRequest的一些參數(XSSFilter(自定義過濾器)),如:過濾低俗文字、危險字符等。   web.xml
<filter> <filter-name>encoding</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encoding</filter-name> <servlet-name>/*</servlet-name> </filter-mapping> (2)攔截器(Interceptor):它依賴於web框架,在SpringMVC中就是依賴於SpringMVC框架。
  在實現上,基於Java的反射機制,屬於面向切面編程(AOP)的一種運用,就是在service或者一個方法前,調用一個方法,或者在方法後,調用一個方法,好比動態代理就是攔截器的簡單實現,在調用方法前打印出字符串(或者作其它業務邏輯的操做),也能夠在調用方法後打印出字符串,甚至在拋出異常的時候作業務邏輯的操做。
  因爲攔截器是基於web框架的調用,所以可使用Spring的依賴注入(DI)進行一些業務操做,同時一個攔截器實例在一個controller生命週期以內能夠屢次調用
  可是缺點是隻能對controller請求進行攔截,對其餘的一些好比直接訪問靜態資源的請求則沒辦法進行攔截處理
  登錄驗證
SpringMVC的配置文件
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**" /> <bean class="com.scorpios.atcrowdfunding.web.LoginInterceptor"></bean> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/**" /> <bean class="com.scorpios.atcrowdfunding.web.AuthInterceptor"></bean> </mvc:interceptor> </mvc:interceptors> 總結 (1)Filter須要在web.xml中配置,依賴於Servlet; (2)Interceptor須要在SpringMVC中配置,依賴於框架; (3)Filter的執行順序在Interceptor以前,具體的流程見下圖;

(4)區別:攔截器(Interceptor)是基於Java的反射機制,而過濾器(Filter)是基於函數回調
  從靈活性上說攔截器功能更強大些,Filter能作的事情,都能作,並且能夠在請求前,請求後執行,比較靈活
  Filter主要是針對URL地址作一個編碼的事情、過濾掉沒用的參數、安全校驗(比較泛的,好比登陸不登陸之類),
  太細的話,仍是建議用interceptor。不過仍是根據不一樣狀況選擇合適的。

 

3. Hibernate && Mybatis

1. Hibernate防止Sql注入

1.對參數名稱named parameter進行綁定:
    String hql = "from InventoryTask it where it.orgId=:orgId";
    Session session = getSession();
    Query query=session.createQuery(hql);
    query.setString("orgId",orgId);
    List list = query.list();
    if(list!=null&&list.size()!=0){
       return (InventoryTask)list.get(0);
    }else{
       return null;
    }
    
2.對參數位置positional parameter進行邦定:
      String hql = "from InventoryTask it where it.orgId=?,it.orgName";
      Session session = getSession();
      Query query=session.createQuery(hql);
      query.setString("0",orgId);
      query.setString(1,orgName)
      List list = query.list();
      if(list!=null&&list.size()!=0){
          return (InventoryTask)list.get(0);
      }else{
          return null;
      }
  
3.setParameter()方法:
    Query query=session.createQuery(hql); 
    query.setParameter(「name」,name,Hibernate.STRING);
4.setProperties()方法: Entity entity=new Entity(); entity.setXx(「xx」); entity.setYy(100); Query query=session.createQuery(「from Entity c where c.xx=:xx and c.yy=:yy 」);  query.setProperties(entity); 5.HQL拼接方法,這種方式是最經常使用,並且容易忽視且容易被注入的,一般作法就是對參數的特殊字符進行過濾,推薦使用 Spring工具包的StringEscapeUtils.escapeSql()方法對參數進行過濾:   import org.apache.commons.lang.StringEscapeUtils;   public static void main(String[] args) {     String str = StringEscapeUtils.escapeSql("'");     System.out.println(str);   }   StringEscapeUtils.escapeSql();    /**      * <p>Escapes the characters in a <code>String</code> to be suitable to pass to      * an SQL query.</p>      *      * <p>For example,      * <pre>statement.executeQuery("SELECT * FROM MOVIES WHERE TITLE='" +       *   StringEscapeUtils.escapeSql("McHale's Navy") +       *   "'");</pre>      * </p>      *      * <p>At present, this method only turns single-quotes into doubled single-quotes      * (<code>"McHale's Navy"</code> => <code>"McHale''s Navy"</code>). It does not      * handle the cases of percent (%) or underscore (_) for use in LIKE clauses.</p>      *      * see http://www.jguru.com/faq/view.jsp?EID=8881      * @param str  the string to escape, may be null      * @return a new String, escaped for SQL, <code>null</code> if null string input      */     public static String escapeSql(String str) {         if (str == null) {             return null;         }         return StringUtils.replace(str, "'", "''");     }   //輸出結果:''

2. Mybatis 防止Sql注入

 #{}:#{}是通過預編譯的,是安全的,至關於JDBC中的PreparedStatement。

    ${}:是未通過預編譯的,僅僅是取變量的值,是非安全的,存在SQL注入。

    在編寫MyBatis的映射語句時,儘可能採用「#{xxx}」這樣的格式。若不得不使用「${xxx}」這樣的參數,要手工地作好過濾工做,來防止SQL注入攻擊。

3. Mybatis # $

#{} : 解析爲一個 JDBC 預編譯語句(prepared statement)的參數標記符,一個 #{ } 被解析爲一個參數佔位符 。web

${}: 僅僅爲一個純碎的 string 替換,在動態 SQL 解析階段將會進行變量替換。面試

一、#將傳入的數據都當成一個字符串,會對自動傳入的數據加一個雙引號。
  如:where username=#{username},若是傳入的值是111,那麼解析成sql時的值爲where username="111", 若是傳入的值是id,則解析成的sql爲where username="id". 
二、$將傳入的數據直接顯示生成在sql中。
  如:where username=${username},若是傳入的值是111,那麼解析成sql時的值爲where username=111;
  若是傳入的值是;drop table user;,則解析成的sql爲:select id, username, password, role from user where username=;drop table user;
三、#方式可以很大程度防止sql注入,$方式沒法防止Sql注入。
四、$方式通常用於傳入數據庫對象,例如傳入表名.
五、通常能用#的就別用$,若不得不使用「${xxx}」這樣的參數,要手工地作好過濾工做,來防止sql注入攻擊。
六、在MyBatis中,「${xxx}」這樣格式的參數會直接參與SQL編譯,從而不能避免注入攻擊。但涉及到動態表名和列名時,只能使用「${xxx}」這樣的參數格式。因此,這樣的參數須要咱們在代碼中手工進行處理來防止注入。
【結論】在編寫MyBatis的映射語句時,儘可能採用「#{xxx}」這樣的格式。若不得不使用「${xxx}」這樣的參數,要手工地作好過濾工做,來防止SQL注入攻擊。

4. Mybatis 實現 in

foreach語句實現IN查詢
/** foreach語句中, collection屬性的參數類型可使:List、數組、map集合 ​ collection: 必須跟mapper.java中@Param標籤指定的元素名同樣 ​ item: 表示在迭代過程當中每個元素的別名,能夠隨便起名,可是必須跟元素中的#{}裏面的名稱同樣。    index:表示在迭代過程當中每次迭代到的位置(下標)    open:前綴, sql語句中集合都必須用小括號()括起來 ​ close:後綴    separator:分隔符,表示迭代時每一個元素之間以什麼分隔 */
    1)若是是list,因此collention裏就要寫list, 2)若是是array,則就要寫array。 3)當查詢的參數有多個時,有兩種方式能夠實現,一種是使用@Param("xxx")進行參數綁定,另外一種能夠經過Map來傳參數。 4)若是是item表示的就是查詢的參數,由於是對象,因此就要獲取其屬性值,也就是object.userId。 
1. list
List<User> selectByIdList(List idList);
 
<select id="selectByIdList" resultMap="BaseResultMap">
    SELECT
    <include refid="Base_Column_List" />
    from t_user
    WHERE id IN
    <foreach collection="list" item="id" index="index" open="(" close=")" separator=",">
      #{id}
    </foreach>
</select>

2. array
List<User> selectByIdArray(String[] idList);
 
<select id="selectByIdArray" resultMap="BaseResultMap">
    SELECT
    <include refid="Base_Column_List" />
    from t_user
    WHERE id IN
    <foreach collection="array" item="id" index="index" open="(" close=")" separator=",">
      #{id}
    </foreach>
</select>

3. 多個參數:當查詢的參數有多個時,有兩種方式能夠實現,一種是使用@Param("xxx")進行參數綁定,另外一種能夠經過Map來傳參數

1)@Param("xxx")方式 List
<User> selectByNameAndIdArray(@Param("name")String name, @Param("ids")String[] idList); <select id="selectByNameAndIdArray" resultMap="BaseResultMap"> SELECT <include refid="Base_Column_List" /> from t_user WHERE name=#{name,jdbcType=VARCHAR} and id IN <foreach collection="idList" item="id" index="index" open="(" close=")" separator=","> #{id} </foreach> </select> 2)Map方式 Map<String, Object> params = new HashMap<String, Object>(2); params.put("name", name); params.put("idList", ids); mapper.selectByIdMap(params); <select id="selectByIdMap" resultMap="BaseResultMap"> select <include refid="Base_Column_List" /> from t_user where name = #{name} and ID in <foreach item="item" index="index" collection="idList" open="(" separator="," close=")"> #{item} </foreach> </select>

5. mybais count

resultType

mybatis返回count(*)的整數值

int selectNums();
<select id="selectNums" resultType="java.lang.Integer"> select count(*) from tableName </select>

6. mybatis中傳入String類型參數

1. 在接口參數里加上mybatis中的@param註解(優先)
List<User> findUserByName(@Param("name")String name);

<select id="findUserByName" parameterType="java.lang.String" resultType="com.entity.User">
    SELECT id,name FROM t_user where id = '1'
       <if test="name!= null and name!= ''">
           AND name LIKE concat('%',#{name},'%')
       </if>
</select> 2. 在xml的if裏用"_parameter" 表明參數
List<User> findUserByName(String name);

<select id="findUserByName" parameterType="java.lang.String" resultType="com.entity.User">
    SELECT id,name FROM t_user  where id = '1'
       <if test="_parameter!= null and _parameter!= ''">
           AND name LIKE concat('%',#{name},'%')
       </if>
</select> _parameter不能區分多個參數,而@param能。因此@param能傳多個這樣的參數 
注意看,是在if test=驗證的時候發生的 「There is no getter for property named in ‘class java.lang.String’」,而並不是是and username = #{username} 的時候發生的錯誤。

 

4. ThreadLocal

ThreadLocl 主要用於線程安全地共享某個變量

1. 底層

ThreadLocalMap
Entry(ThreadLocal<?>, Object)

什麼是ThreadLocal?
/***
ThreadLocal類顧名思義能夠理解爲線程本地變量。
也就是說若是定義了一個ThreadLocal,每一個線程往這個ThreadLocal中讀寫是線程隔離,互相之間不會影響的。
它提供了一種將可變數據經過每一個線程有本身的獨立副本從而實現線程封閉的機制。 *
*/ 它大體的實現思路是怎樣的? /*** Thread類有一個類型爲ThreadLocal.ThreadLocalMap的實例變量threadLocals,
也就是說每一個線程有一個本身的ThreadLocalMap
ThreadLocalMap有本身的獨立實現,能夠簡單地將它的key視做ThreadLocal,value爲代碼中放入的值(實際上key並非ThreadLocal自己,而是它的一個弱引用)。
每一個線程在往某個ThreadLocal裏塞值的時候,都會往本身的ThreadLocalMap裏存,讀也是以某個ThreadLocal做爲引用,在本身的map裏找對應的key,從而實現了線程隔離。 *
*/

2. ThreadLocal和線程池

線程池(核心線程,銷燬線程)

反作用(髒數據,內存溢出)

ThreadLocl 主要用於線程安全地共享某個變量 ThreadLocl 主要會產生髒數據和內存泄露。這兩個問題一般是在線程池的線程中使用ThreadLocal 引起的,由於線程池有線程複用和內存常駐兩個特色。

1.髒數據 線程複用會產生髒數據。因爲線程池會重用Thread對象,那麼與Thread綁定的類靜態屬性也會被重用。
  若是在實現線程run() 方法中不顯示的調用remove() 清理與線程相關的ThreadLocal 信息。
  若是先一個線程不調用set() 設置初始值,那麼就get() 到重用信息,包括ThreadLocl 所關聯線對象的值。 2.內存泄露 在源碼註釋中提示使用static 關鍵字來修改ThreadLocal。
  在此場景下,寄但願於ThreadLocal對象失去引用後,觸發弱引用機制來回收Entry 的Value 就不現實了。
  在上例中,若是不進行remove() 操做,那麼這個線程執行完成後,經過ThreadLocal 對象持有的string對象是不會被釋放的。 以上兩個問題解決的辦法很簡單,就是每次用完ThreadLocal 時,必須調用remove() 方法清理

JAVA源碼系列之JAVA併發ThreadLocal

 

5. Volatile

 

 

 

6. synchronized

Lock與synchronized有如下區別:

  1. Lock是一個接口,而synchronized是關鍵字。
  2. synchronized會自動釋放鎖,而Lock必須手動釋放鎖。
  3. Lock可讓等待鎖的線程響應中斷,而synchronized不會,線程會一直等待下去。
  4. 經過Lock能夠知道線程有沒有拿到鎖,而synchronized不能。
  5. Lock能提升多個線程讀操做的效率。
  6. synchronized能鎖住類、方法和代碼塊,而Lock是塊範圍內的

 

7. CAS

8. CountDownLatch

 

http://www.javashuo.com/article/p-hjltfdao-dw.html

9. 公平鎖 & 非公平鎖

公平鎖:FIFO 獲取不到鎖的時候,會自動加入隊列,等待線程釋放後,隊列的第一個線程獲取鎖

非公平鎖: 獲取不到鎖的時候,會自動加入隊列,等待線程釋放鎖後全部等待的線程同時去競爭

它們的差異在於非公平鎖會有更多的機會去搶佔鎖。
可重入: 同一個線程能夠反覆獲取鎖屢次,而後須要釋放屢次
synchronized 是非公平鎖,能夠重入。

ReentrantLock內部擁有一個Sync內部類,該內部類繼承自AQS,該內部類有兩個子類FairSync和NonfairSync,分別表明了公平鎖和非公平鎖,ReentrantLock默認使用非公平鎖
  /** * true 表示 ReentrantLock 的公平鎖 */ private ReentrantLock lock = new ReentrantLock(true);

 

10. HTTPS

應用層協議:HTTPS

 

 

 

 
一個HTTPS請求實際上包含了兩次HTTP傳輸,能夠細分爲8步。

1. 客戶端發起HTTPS請求:請求攜帶了瀏覽器支持的加密算法和哈希算法
  客戶端向服務器發起HTTPS請求,鏈接到服務器的443端口。 

2. 服務端的配置:服務器收到請求,選擇瀏覽器支持的加密算法和哈希算法。
  服務器端有一個密鑰對,即公鑰和私鑰,是用來進行非對稱加密使用的,服務器端保存着私鑰,不能將其泄露,公鑰能夠發送給任何人。採用HTTPS協議的服務器必需要有一套數字證書。

3. 傳送證書:服務器將本身的CA 證書(公鑰)發送給客戶端。

  這個證書其實就是公鑰,只是包含了不少信息,如證書的頒發機構,過時時間等等。

4. 客戶端解析證書(TLS)

  客戶端收到服務器端的公鑰以後,會對公鑰進行檢查,驗證其合法性,
  若是發現發現公鑰有問題,那麼HTTPS傳輸就沒法繼續。
  若是公鑰合格,那麼客戶端會生成一個隨機值,這個隨機值就是用於進行對稱加密的密鑰,咱們將該密鑰稱之爲client key,即客戶端密鑰,這樣在概念上和服務器端的密鑰容易進行區分。
  而後用服務器的公鑰對客戶端密鑰進行非對稱加密,這樣客戶端密鑰就變成密文了,
  至此,HTTPS中的第一次HTTP請求結束。
  這部分工做是有客戶端的TLS來完成的,首先會驗證公鑰是否有效,好比頒發機構,過時時間等等,若是發現異常,則會彈出一個警告框,提示證書存在問題。若是證書沒有問題,那麼就生成一個隨即值。而後用證書對該隨機值進行加密。就好像上面說的,把隨機值用鎖頭鎖起來,這樣除非有鑰匙,否則看不到被鎖住的內容。
5. 傳送加密信息
  客戶端會發起HTTPS中的第二個HTTP請求,將加密以後的客戶端密鑰發送給服務器。   這部分傳送的是用證書加密後的隨機值R(私鑰),目的就是讓服務端獲得這個隨機值R,之後客戶端和服務端的通訊就能夠經過這個隨機值R來進行加密解密了。
6. 服務端解密信息
  服務器接收到客戶端發來的密文以後,會用本身的私鑰對其進行非對稱解密,解密以後的明文就是客戶端密鑰(隨機數 R)
  而後把內容用客戶端密鑰隨機數 R進行對稱加密,這樣數據就變成了密文。   服務端用私鑰解密後,獲得了客戶端傳過來的隨機值(私鑰),而後把內容經過該值進行對稱加密。
  所謂對稱加密就是,將信息和私鑰經過某種算法混合在一塊兒,這樣除非知道私鑰,否則沒法獲取內容,而正好客戶端和服務端都知道這個私鑰,因此只要加密算法夠彪悍,私鑰夠複雜,數據就夠安全。
7. 傳輸加密後的信息
  而後服務器將加密後的密文發送給客戶端。(服務器以隨機數 R 爲密鑰把傳輸內容使用對稱加密算法加密並傳輸給瀏覽器)。   這部分信息是服務端用私鑰加密後的信息,能夠在客戶端被還原
8. 客戶端解密信息
  客戶端收到服務器發送來的密文,用客戶端密鑰(隨機數 R)對其進行對稱解密,獲得服務器發送的數據。這樣HTTPS中的第二個HTTP請求結束,整個HTTPS傳輸完成。   客戶端用以前生成的私鑰解密服務段傳過來的信息,因而獲取瞭解密後的內容。整個過程第三方即便監聽到了數據,也一籌莫展。

 

11. QPS過大怎麼辦?

/**
儘可能使用緩存,包括用戶緩存,信息緩存等,多花點內存來作緩存,能夠大量減小與數據庫的交互,提升性能。

用jprofiler等工具找出性能瓶頸,減小額外的開銷。

優化數據庫查詢語句,減小直接使用hibernate等工具的直接生成語句(僅耗時較長的查詢作優化)。

優化數據庫結構,多作索引,提升查詢效率。

統計的功能儘可能作緩存,或按天天一統計或定時統計相關報表,避免須要時進行統計的功能。

能使用靜態頁面的地方儘可能使用,減小容器的解析(儘可能將動態內容生成靜態html來顯示)。

解決以上問題後,使用服務器集羣來解決單臺的瓶頸問題。
*/

 

12. linux基本命令

1. Linux三劍客(grep、sed、awk)

Linux三劍客(grep、sed、awk)
grep:文本過濾(模式:pattern)工具,grep, egrep
sed:是一種流編輯器,它一次處理一行內容。處理時,把當前處理的行存儲在臨時緩衝區中
awk:報告生成器,格式化文本輸出,有多種版本:New awk(nawk),GNU awk( gawk)

-記住三個命令的運用形式
     grep    '字符'       文件
     sed     '命令'       文件
     awk    '條件{命令}'   文件
-單引號內就是正則表達式的用法


Linux下使用Shell截取文件一部份內容保存到新的文件中

1. 肯定有本身業務有關的日誌在文件中的行數

 grep -n "業務有關的關鍵字" filename

 根據關鍵字的搜索結果,綠色數字爲關鍵字出如今文件中所在的行數,這樣就能夠大概估算關鍵字出現的行的範圍了。

2. 截取指定行之間的日誌到新的文件中 

 sed -n '開始行數,結束行數p'  待截取的文件  >> 保存的新文件 

 

2. 受權

chown:用來更改某個目錄或文件的用戶名和用戶組

chmod:用來更改某個目錄或文件的訪問權限

`ll`命令查看目錄下文件

"drwxr-xr-x" 可見一共有十位。-[rw-][r--][r--].其中第一個[-]表明的是類型,其中第一位爲d表明目錄,每三位表明一個權限位

d:目錄
rwx: 可讀、可寫、可執行   2-4位表明全部者擁有的權限
r-x: 可讀、可執行        5-7位表明羣組擁有的權限
r-x: 可讀、可執行        8-10位表明其餘人擁有的權限

十進制表示
/**
r : 4 
w : 2
x : 1
- :  0 
/**

權限操做
/**
+ 表示添加權限
- 表示刪除權限
= 重置權限
修改文件權限
*/

位置
/**
u:表明文件全部者(user)
g: 表明全部者所在的羣組(group)
o:表明其餘人,但不是u和g(other)
a:a和一塊兒指定ugo效果同樣
*/

/**
chmod o+w test.txt :表示給其餘人授予寫test.txt這個文件的權限
chmod go-rw test.txt : 表示羣組和其餘人刪除對test.txt文件的讀寫權限
chmod ugo+r test.txt:全部人皆可讀取
chmod a+r text.txt:全部人皆可讀取
chmod ug+w,o-w text.txt:設爲該檔案擁有者,與其所屬同一個羣體者可寫入,但其餘之外的人則不可寫入
chmod u+x test.txt: 建立者擁有執行權限 
chmod -R a+r ./www/ :將www下的全部檔案與子目錄皆設爲任何人可讀取
chmod a-x test.txt :收回全部用戶的對test.txt的執行權限
chmod 777 test.txt: 全部人可讀,寫,執行
*/

修改目錄權限
/**
chmod 700   /opt/elasticsearch  #修改目錄權限
chmod -R 744 /opt/elasticsearch  #修改目目錄如下全部的權限   
-R             # 以遞歸方式更改全部的文件及子目錄
 chown 修改用戶組  修改 test.txt 目錄所屬用戶爲 root,用戶組爲 root
chown -R root:root test.txt   
-rw-r--r--. 1 root root   55 8月  24 17:25 test.txt
 */

常見權限
/**
-rw------- (600) 只有全部者纔有讀和寫的權限。
-rw-r--r-- (644) 只有全部者纔有讀和寫的權限,羣組和其餘人只有讀的權限。
-rw-rw-rw- (666) 每一個人都有讀寫的權限
-rwx------ (700) 只有全部者纔有讀,寫和執行的權限。
-rwx--x--x (711) 只有全部者纔有讀,寫和執行的權限,羣組和其餘人只有執行的權限。
-rwxr-xr-x (755) 只有全部者纔有讀,寫,執行的權限,羣組和其餘人只有讀和執行的權限。
-rwxrwxrwx (777) 每一個人都有讀,寫和執行的權限
*/

實踐 在用Elasticsearch的時候是少不了給添加用戶受權
/**
chmod 400 test.txt        #修改text.txt爲可讀文件
vi text.txt               #執行該命令後,該文件就沒法進行寫入操做 提示下面信息
-- INSERT -- W10: Warning: Changing a readonly file
chmod 777 text.txt 
-rwxrwxrwx. 1 root root   55 8月  24 17:25 test.txt
chmod rwxr--r-- test.txt   #異常,不能使用該命令來修改權限
*/

 

3. root權限

方法一:修改 /etc/sudoers 文件,找到下面一行,把前面的註釋(#)去掉
## Allows people in group wheel to run all commands
%wheel    ALL=(ALL)    ALL
而後修改用戶,使其屬於root組(wheel),命令以下:
#usermod -g root tommy
修改完畢,如今能夠用tommy賬號登陸,而後用命令 su – ,便可得到root權限進行操做。

方法二:修改 /etc/sudoers 文件,找到下面一行,在root下面添加一行,以下所示:
## Allow root to run any commands anywhere
root    ALL=(ALL)     ALL
tommy ALL=(ALL) ALL
修改完畢,如今能夠用tommy賬號登陸,而後用命令 sudo – ,便可得到root權限進行操做。

方法三:修改 /etc/passwd 文件,找到以下行,把用戶ID修改成 0 ,以下所示:
tommy:x:0:33:tommy:/data/webroot:/bin/bash

 

4. 查看進程和端口

一、lsof -i:端口號
二、netstat -tunlp|grep 端口號
均可以查看指定端口被哪一個進程佔用的狀況

lsof -i 用以顯示符合條件的進程狀況,lsof(list open files)是一個列出當前系統打開文件的工具。
lsof -i:端口號,用於查看某一端口的佔用狀況,好比查看22號端口使用狀況,lsof -i:22
netstat -tunlp用於顯示tcp,udp的端口和進程等相關狀況
netstat -tunlp|grep 端口號,用於查看指定端口號的進程狀況,如查看22端口的狀況,netstat -tunlp|grep 22

 

5. 查看全局

1、查看CPU信息
# 總核數 = 物理CPU個數 X 每顆物理CPU的核數
# 總邏輯CPU數 = 物理CPU個數 X 每顆物理CPU的核數 X 超線程數

# 查看物理CPU個數
cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l

# 查看每一個物理CPU中core的個數(即核數)
cat /proc/cpuinfo| grep "cpu cores"| uniq

# 查看邏輯CPU的個數
cat /proc/cpuinfo| grep "processor"| wc -l

# 查看CPU信息(型號)
cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c


#CPU負載信息,使用top 命令

2、查看內存信息
1)cat /proc/meminfo
2)free 命令

3、查看磁盤信息
1)fdisk -l
2)iostat -x 10    查看磁盤IO的性能

 

13. 數據庫索引最左原則

最左前綴原則
mysql創建多列索引(聯合索引)有最左前綴的原則,即最左優先,如:

若是有一個2列的索引(col1,col2),則已經對(col1)、(col1,col2)上創建了索引; 若是有一個3列索引(col1,col2,col3),則已經對(col1)、(col1,col2)、(col1,col2,col3)上創建了索引;

一、b+樹的數據項是複合的數據結構,好比(name,age,sex)的時候,b+樹是按照從左到右的順序來創建搜索樹的,好比當(張三,20,F)這樣的數據來檢索的時候,b+樹會優先比較name來肯定下一步的所搜方向,若是name相同再依次比較age和sex,最後獲得檢索的數據;但當(20,F)這樣的沒有name的數據來的時候,b+樹就不知道第一步該查哪一個節點,由於創建搜索樹的時候name就是第一個比較因子,必需要先根據name來搜索才能知道下一步去哪裏查詢。
二、好比當(張三,F)這樣的數據來檢索時,b+樹能夠用name來指定搜索方向,但下一個字段age的缺失,因此只能把名字等於張三的數據都找到,而後再匹配性別是F的數據了, 這個是很是重要的性質,即索引的最左匹配特性。(這種狀況沒法用到聯合索引)

關於最左前綴的使用,有下面兩條說明:
1. 最左前綴匹配原則,很是重要的原則,mysql會一直向右匹配直到遇到範圍查詢(>、<、between、like)就中止匹配,好比a = 1 and b = 2 and c > 3 and d = 4 若是創建(a,b,c,d)順序的索引,d是用不到索引的,若是創建(a,b,d,c)的索引則均可以用到,a,b,d的順序能夠任意調整。
2. =和in能夠亂序,好比a = 1 and b = 2 and c = 3 創建(a,b,c)索引能夠任意順序,mysql的查詢優化器會幫你優化成索引能夠識別的形式

 

14. B+樹

B+ 樹是一種樹數據結構,是一個n叉樹,每一個節點一般有多個孩子,一顆B+樹包含根節點、內部節點和葉子節點。根節點多是一個葉子節點,也多是一個包含兩個或兩個以上孩子節點的節點。 

B+ 樹一般用於數據庫和操做系統的文件系統中。 NTFS, ReiserFS, NSS, XFS, JFS, ReFS 和BFS等文件系統都在使用B+樹做爲元數據索引。 

B+ 樹的特色是可以保持數據穩定有序,其插入與修改擁有較穩定的對數時間複雜度。 

B+ 樹元素自底向上插入。 

全部的葉子結點中包含了所有關鍵字的信息,及指向含有這些關鍵字記錄的指針,且葉子結點自己依關鍵字的大小自小而大的順序連接。(而B 樹的葉子節點並無包括所有須要查找的信息) 

全部的非終端結點能夠當作是索引部分,結點中僅含有其子樹根結點中最大(或最小)關鍵字。(而B 樹的非終節點也包含須要查找的有效信息)

/** B樹 
    每一個節點都存儲key和data,全部節點組成這棵樹,而且葉子節點指針爲null。
    B樹優勢在於,因爲B樹的每個節點都包含key和value,所以常常訪問的元素可能離根節點更近,所以訪問也更迅速。

B+樹 
    只有葉子節點存儲data,葉子節點包含了這棵樹的全部鍵值,葉子節點不存儲指針。全部非終端節點當作是索引,節點中僅含有其子樹根節點最大(或最小)的關鍵字,不包含查找的有效信息。B+樹中全部葉子節點都是經過指針鏈接在一塊兒。

   B+ 樹的優勢在於:
    因爲B+樹在內部節點上不包含數據信息,所以在內存頁中可以存放更多的key。 數據存放的更加緊密,具備更好的空間局部性。所以訪問葉子節點上關聯的數據也具備更好的緩存命中率。
    B+樹的葉子結點都是相鏈的,所以對整棵樹的便利只須要一次線性遍歷葉子結點便可。並且因爲數據順序排列而且相連,因此便於區間查找和搜索。而B樹則須要進行每一層的遞歸遍歷。相鄰的元素可能在內存中不相鄰,因此緩存命中性沒有B+樹好。

B和B+樹的區別在於,B+樹的非葉子結點只包含導航信息,不包含實際的值,全部的葉子結點和相連的節點使用鏈表相連,便於區間查找和遍歷。

總結:爲何使用B+樹?
    1.文件很大,不可能所有存儲在內存中,故要存儲到磁盤上 
    2.索引的結構組織要儘可能減小查找過程當中磁盤I/O的存取次數(爲何使用B-/+Tree,還跟磁盤存取原理有關,具體看下邊分析) 
    3.局部性原理與磁盤預讀,預讀的長度通常爲頁(page)的整倍數,(在許多操做系統中,頁得大小一般爲4k) 
    4.數據庫系統巧妙利用了磁盤預讀原理,將一個節點的大小設爲等於一個頁,這樣 每一個節點只須要一次I/O 就能夠徹底載入,(因爲節點中有兩個數組,因此地址連續)。而紅黑樹這種結構, h 明顯要深的多。因爲邏輯上很近的節點(父子)物理上可能很遠,沒法利用局部性。

爲何B+樹比B樹更適合作索引?
    1.B+樹磁盤讀寫代價更低: B+的內部結點並無指向關鍵字具體信息的指針,即內部節點不存儲數據。所以其內部結點相對B 樹更小。若是把全部同一內部結點的關鍵字存放在同一盤塊中,那麼盤塊所能容納的關鍵字數量也越多。一次性讀入內存中的須要查找的關鍵字也就越多。相對來講IO讀寫次數也就下降了。
    2.B+tree的查詢效率更加穩定: 因爲非終結點並非最終指向文件內容的結點,而只是葉子結點中關鍵字的索引。因此任何關鍵字的查找必須走一條從根結點到葉子結點的路。全部關鍵字查詢的路徑長度相同,致使每個數據的查詢效率至關。

在MySQL中,最經常使用的兩個存儲引擎是MyISAM和InnoDB,它們對索引的實現方式是不一樣的。
    MyISAM data存的是數據地址。索引是索引,數據是數據。
    InnoDB data存的是數據自己。索引也是數據。
*/

 

15. GC

JVM系列之五:垃圾回收

1. 互相引用會不會清除?

循環引用,就看這個循環引用是否掛在根上,
假設掛在根上且這個根還被JVM的Java代碼所運行的話,就不會GC掉,假設說這個根已經被釋放掉了。這個對象不掛在跟上了。那個這個對象就會被GC掉。

 

2. java dump文件怎麼生成和分析-JVM調優

1. 查看整個JVM內存狀態 

jmap -heap [pid]

2. 查看JVM堆中對象詳細佔用狀況
jmap
-histo [pid] 3. 導出整個JVM 中內存信息,能夠利用其它工具打開dump文件分析,例如jdk自帶的visualvm工具 jmap -dump:file=文件名.dump [pid] jmap -dump:format=b,file=文件名 [pid] format=b指定爲二進制格式文件

3. 可視化工具備哪些

1.JConsole
  JConsole工具在JDK/bin目錄下,啓動JConsole後,將自動搜索本機運行的jvm進程,不須要jps命令來查詢指定。雙擊其中一個jvm進程便可開始監控,也可以使用「遠程進程」來鏈接遠程服務器。
  進入JConsole主界面,有「概述」、「內存」、「線程」、「類」、「VM摘要」和"Mbean"六個頁籤:
2.VisualVM
  VisualVM是一個集成多個JDK命令行工具的可視化工具。VisualVM基於NetBeans平臺開發,它具有了插件擴展功能的特性,經過插件的擴展,可用於顯示虛擬機進程及進程的配置和環境信息(jps,jinfo),監視應用程序的CPU、GC、堆、方法區及線程的信息(jstat、jstack)等。VisualVM在JDK/bin目錄下。
3.jprofiler

 

16. 去除ArrayList裏面的偶數

迭代器

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class A1 {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(6);
        System.out.println("刪除前:" + list);

        int size = list.size();
        Iterator<Integer> it = list.iterator();

        for (int i = 0; i < size; i++) {
            if (it.next() % 2 == 0) {
                it.remove();
            }
        }

        System.out.println("刪除後:" + list);
    }
}

 

二面

1. GC

JVM系列之五:垃圾回收

 CMS: 標記清除

2. 數據庫隔離級別以及實現原理

美團點評面試20190515

對應隔離級別
    1.READ UNCOMMITTED:讀未提交,不處理,會出現髒讀,不可重複讀,幻讀。
    2.READ COMMITTED:讀已提交,只讀提交的數據,無髒讀,但這種級別會出現讀取舊數據的現象,不可重複讀,大多數數據庫系統的默認隔離級別。
    3.REPEATABLE READ:可重複讀,加行鎖,兩次讀之間不會有修改,無髒讀無重複讀;保證了每行的記錄的結果是一致的。可是沒法解決幻讀
    4.SERIALIZABLE: 串行化,加表鎖,強制事務串行執行,無全部問題,不會出現髒讀,不可重複讀,幻讀。因爲他大量加上鎖,致使大量的請求超時,所以性能會比較低下,須要數據一致性且併發量不須要那麼大的時候纔可能考慮這個隔離級別。

隔離級別原理
READ_UNCOMMITED 的原理:
    1,事務對當前被讀取的數據不加鎖;
    2,事務在更新某數據的瞬間(就是發生更新的瞬間),必須先對其加 行級共享鎖,直到事務結束才釋放。  
   // 1,事務1讀取某行記錄時,事務2也能對這行記錄進行讀取、更新;當事務2對該記錄進行更新時,事務1再次讀取該記錄,能讀到事務2對該記錄的修改版本,即便該修改還沒有被提交。
   // 2,事務1更新某行記錄時,事務2不能對這行記錄作更新,直到事務1結束。

READ_COMMITED 的原理:
    1,事務對當前被讀取的數據加 行級共享鎖(當讀到時才加鎖),一旦讀完該行,當即釋放該行級共享鎖;
    2,事務在更新某數據的瞬間(就是發生更新的瞬間),必須先對其加 行級排他鎖,直到事務結束才釋放。
   // 1,事務1讀取某行記錄時,事務2也能對這行記錄進行讀取、更新;當事務2對該記錄進行更新時,事務1再次讀取該記錄,讀到的只能是事務2對其更新前的版本,要不就是事務2提交後的版本。
   // 2,事務1更新某行記錄時,事務2不能對這行記錄作更新,直到事務1結束。

REPEATABLE READ 的原理:
    1,事務在讀取某數據的瞬間(就是開始讀取的瞬間),必須先對其加 行級共享鎖,直到事務結束才釋放;
    2,事務在更新某數據的瞬間(就是發生更新的瞬間),必須先對其加 行級排他鎖,直到事務結束才釋放。 
    // 1,事務1讀取某行記錄時,事務2也能對這行記錄進行讀取、更新;當事務2對該記錄進行更新時,事務1再次讀取該記錄,讀到的仍然是第一次讀取的那個版本。
    // 2,事務1更新某行記錄時,事務2不能對這行記錄作更新,直到事務1結束。

SERIALIZABLE 的原理:
    1,事務在讀取數據時,必須先對其加 表級共享鎖 ,直到事務結束才釋放;
    2,事務在更新數據時,必須先對其加 表級排他鎖 ,直到事務結束才釋放。
    // 1,事務1正在讀取A表中的記錄時,則事務2也能讀取A表,但不能對A表作更新、新增、刪除,直到事務1結束。
    // 2,事務1正在更新A表中的記錄時,則事務2不能讀取A表的任意記錄,更不可能對A表作更新、新增、刪除,直到事務1結束。

數據庫鎖// 數據庫鎖出現的目的:處理併發問題 鎖分類 從數據庫系統角度分爲三種:排他鎖、共享鎖、更新鎖。 從程序員角度分爲兩種:一種是悲觀鎖,一種樂觀鎖。 悲觀鎖按使用性質劃分:排他鎖、共享鎖、更新鎖。 悲觀鎖按做用範圍劃分:行鎖、表鎖。 樂觀鎖實現方式:版本號,時間戳。 數據庫規定同一資源上不能同時共存共享鎖和排他鎖。 1、悲觀鎖(Pessimistic Lock) 顧名思義,很悲觀,每次去拿數據的時候都認爲別人會修改,因此每次在拿數據的時候都會上鎖,這樣別人拿這個數據就會block(阻塞),直到它拿鎖。傳統的關係數據庫裏用到了不少這種鎖機制,好比行鎖、表鎖、讀鎖、寫鎖等,都是在操做以前先上鎖。 1. 共享鎖(Share Lock) S鎖,也叫讀鎖,用於全部的只讀數據操做。共享鎖是非獨佔的,容許多個併發事務讀取其鎖定的資源。 性質 1. 多個事務可封鎖同一個共享頁; 2. 任何事務都不能修改該頁; 3. 一般是該頁被讀取完畢,S鎖當即被釋放。 // 在SQL Server中,默認狀況下,數據被讀取後,當即釋放共享鎖。 // 例如,執行查詢語句「SELECT * FROM my_table」時,首先鎖定第一頁,讀取以後,釋放對第一頁的鎖定,而後鎖定第二頁。這樣,就容許在讀操做過程當中,修改未被鎖定的第一頁。 // 例如,語句「SELECT * FROM my_table HOLDLOCK」就要求在整個查詢過程當中,保持對錶的鎖定,直到查詢完成才釋放鎖定。 2. 排他鎖(Exclusive Lock) X鎖,也叫寫鎖,表示對數據進行寫操做。若是一個事務對對象加了排他鎖,其餘事務就不能再給它加任何鎖了。 性質 1. 僅容許一個事務封鎖此頁; 2. 其餘任何事務必須等到X鎖被釋放才能對該頁進行訪問; 3. X鎖一直到事務結束才能被釋放。 // 產生排他鎖的SQL語句以下:select * from ad_plan for update; 3. 更新鎖 U鎖,在修改操做的初始化階段用來鎖定可能要被修改的資源,這樣能夠避免使用共享鎖形成的死鎖現象。 // 由於當使用共享鎖時,修改數據的操做分爲兩步: 1. 首先得到一個共享鎖,讀取數據, 2. 而後將共享鎖升級爲排他鎖,再執行修改操做。 這樣若是有兩個或多個事務同時對一個事務申請了共享鎖,在修改數據時,這些事務都要將共享鎖升級爲排他鎖。這時,這些事務都不會釋放共享鎖,而是一直等待對方釋放,這樣就形成了死鎖。 // 若是一個數據在修改前直接申請更新鎖,在數據修改時再升級爲排他鎖,就能夠避免死鎖。 性質 1. 用來預約要對此頁施加X鎖,它容許其餘事務讀,但不容許再施加U鎖或X鎖; 2. 當被讀取的頁要被更新時,則升級爲X鎖; 3. U鎖一直到事務結束時才能被釋放。 4. 行鎖 鎖的做用範圍是行級別。 行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的機率最低,併發度也最高。 5. 表鎖 鎖的做用範圍是整張表。 表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的機率最高,併發度最低。 6. 頁面鎖 頁面鎖:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度通常。 // 數據庫可以肯定那些行須要鎖的狀況下使用行鎖,若是不知道會影響哪些行的時候就會使用表鎖。 // 舉個例子,一個用戶表user,有主鍵id和用戶生日birthday。 // 當你使用update … where id=?這樣的語句時,數據庫明確知道會影響哪一行,它就會使用行鎖; // 當你使用update … where birthday=?這樣的的語句時,由於事先不知道會影響哪些行就可能會使用表鎖。 2、樂觀鎖(Optimistic Lock) 顧名思義,就是很樂觀,每次去拿數據的時候都認爲別人不會修改,因此,不會上鎖。可是在更新的時候會判斷一下在此期間別人有沒有更新這個數據,可使用版本號等機制。 1. 版本號(version) 版本號(記爲version):就是給數據增長一個版本標識,在數據庫上就是表中增長一個version字段,每次更新把這個字段加1,讀取數據的時候把version讀出來,更新的時候比較version,若是仍是開始讀取的version就能夠更新了,若是如今的version比老的version大,說明有其餘事務更新了該數據,並增長了版本號,這時候獲得一個沒法更新的通知,用戶自行根據這個通知來決定怎麼處理,好比從新開始一遍。這裏的關鍵是判斷version和更新兩個動做須要做爲一個原子單元執行,不然在你判斷能夠更新之後正式更新以前有別的事務修改了version,這個時候你再去更新就可能會覆蓋前一個事務作的更新,形成第二類丟失更新,因此你可使用update … where … and version=」old version」這樣的語句,根據返回結果是0仍是非0來獲得通知,若是是0說明更新沒有成功,由於version被改了,若是返回非0說明更新成功。 2. 時間戳(使用數據庫服務器的時間戳) 時間戳(timestamp):和版本號基本同樣,只是經過時間戳來判斷而已,注意時間戳要使用數據庫服務器的時間戳不能是業務系統的時間。 3. 待更新字段 待更新字段:和版本號方式類似,只是不增長額外字段,直接使用有效數據字段作版本控制信息,由於有時候咱們可能沒法改變舊系統的數據庫表結構。假設有個待更新字段叫count,先去讀取這個count,更新的時候去比較數據庫中count的值是否是我指望的值(即開始讀的值),若是是就把我修改的count的值更新到該字段,不然更新失敗。java的基本類型的原子類型對象如AtomicInteger就是這種思想。 4. 全部字段 全部字段:和待更新字段相似,只是使用全部字段作版本控制信息,只有全部字段都沒變化纔會執行更新。

 

3. 樂觀鎖 & 悲觀鎖

悲觀鎖
老是假設最壞的狀況,每次去拿數據的時候都認爲別人會修改,因此每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會阻塞直到它拿到鎖(共享資源每次只給一個線程使用,其它線程阻塞,用完後再把資源轉讓給其它線程)。傳統的關係型數據庫裏邊就用到了不少這種鎖機制,好比行鎖,表鎖等,讀鎖,寫鎖等,都是在作操做以前先上鎖。Java中synchronized和ReentrantLock等獨佔鎖就是悲觀鎖思想的實現。

樂觀鎖
老是假設最好的狀況,每次去拿數據的時候都認爲別人不會修改,因此不會上鎖,可是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可使用版本號機制和CAS算法實現。樂觀鎖適用於多讀的應用類型,這樣能夠提升吞吐量,像數據庫提供的相似於write_condition機制,其實都是提供的樂觀鎖。在Java中java.util.concurrent.atomic包下面的原子變量類就是使用了樂觀鎖的一種實現方式CAS實現的。

兩種鎖的使用場景
從上面對兩種鎖的介紹,咱們知道兩種鎖各有優缺點,不可認爲一種好於另外一種,像樂觀鎖適用於寫比較少的狀況下(多讀場景),即衝突真的不多發生的時候,這樣能夠省去了鎖的開銷,加大了系統的整個吞吐量。但若是是多寫的狀況,通常會常常產生衝突,這就會致使上層應用會不斷的進行retry,這樣反卻是下降了性能,因此通常多寫的場景下用悲觀鎖就比較合適。

 

4. 計算機網絡

OSI七層

5. 逆時針輸出二維矩陣

能夠參考 leetcode54螺旋矩陣:https://leetcode-cn.com/problems/spiral-matrix/

class Solution {
    public List < Integer > spiralOrder(int[][] matrix) {
        List ans = new ArrayList();
        if (matrix.length == 0)
            return ans;
        int r1 = 0, r2 = matrix.length - 1;
        int c1 = 0, c2 = matrix[0].length - 1;
        while (r1 <= r2 && c1 <= c2) {
            for (int c = c1; c <= c2; c++) ans.add(matrix[r1][c]);
            for (int r = r1 + 1; r <= r2; r++) ans.add(matrix[r][c2]);
            if (r1 < r2 && c1 < c2) {
                for (int c = c2 - 1; c > c1; c--) ans.add(matrix[r2][c]);
                for (int r = r2; r > r1; r--) ans.add(matrix[r][c1]);
            }
            r1++;
            r2--;
            c1++;
            c2--;
        }
        return ans;
    }
}

 

三面:項目難點

1. 智能體如今哪裏?

2. 項目難點是什麼?

3. 敏捷開發和傳統開發區別是什麼?

4. 項目管理的角度提升效率?

5. 印象最深的一次面試?

6. 建議:覆盤,及時檢討,及時總結,主動分享,揚長避短。

相關文章
相關標籤/搜索