PIXNET Logo登入

互聯網 - 大數據

跳到主文

本部落格為互聯網熱門頭條訊息管理中心

部落格全站分類:生活綜合

  • 相簿
  • 部落格
  • 留言
  • 名片
  • 3月 15 週三 201722:41
  • spring boot(五):spring data jpa的使用


文章出處
在上篇文章springboot(二):web綜合開發中簡單介紹了一下spring data jpa的基礎性使用,這篇文章將更加全面的介紹spring data jpa 常見用法以及注意事項
使用spring data jpa 開發時,發現國內對spring boot jpa全面介紹的文章比較少案例也比較零碎,因此寫文章總結一下。本人也正在翻譯Spring Data JPA 參考指南,有興趣的同學歡迎聯系我,一起加入翻譯中!
spring data jpa介紹
首先了解JPA是什么?
JPA(Java Persistence API)是Sun官方提出的Java持久化規范。它為Java開發人員提供了一種對象/關聯映射工具來管理Java應用中的關系數據。他的出現主要是為了簡化現有的持久化開發工作和整合ORM技術,結束現在Hibernate,TopLink,JDO等ORM框架各自為營的局面。值得注意的是,JPA是在充分吸收了現有Hibernate,TopLink,JDO等ORM框架的基礎上發展而來的,具有易于使用,伸縮性強等優點。從目前的開發社區的反應上看,JPA受到了極大的支持和贊揚,其中就包括了Spring與EJB3.0的開發團隊。

注意:JPA是一套規范,不是一套產品,那么像Hibernate,TopLink,JDO他們是一套產品,如果說這些產品實現了這個JPA規范,那么我們就可以叫他們為JPA的實現產品。


spring data jpa
Spring Data JPA 是 Spring 基于 ORM 框架、JPA 規范的基礎上封裝的一套JPA應用框架,可使開發者用極簡的代碼即可實現對數據的訪問和操作。它提供了包括增刪改查等在內的常用功能,且易于擴展!學習并使用 Spring Data JPA 可以極大提高開發效率!

spring data jpa讓我們解脫了DAO層的操作,基本上所有CRUD都可以依賴于它來實現


基本查詢
基本查詢也分為兩種,一種是spring data默認已經實現,一種是根據查詢的方法來自動解析成SQL。
預先生成方法
spring data jpa 默認預先生成了一些基本的CURD的方法,例如:增、刪、改等等
1 繼承JpaRepository
public interface UserRepository extends JpaRepository<User, Long> {
}

2 使用默認方法
@Test
public void testBaseQuery() throws Exception {
User user=new User();
userRepository.findAll();
userRepository.findOne(1l);
userRepository.save(user);
userRepository.delete(user);
userRepository.count();
userRepository.exists(1l);
// ...
}

就不解釋了根據方法名就看出意思來
自定義簡單查詢
自定義的簡單查詢就是根據方法名來自動生成SQL,主要的語法是findXXBy,readAXXBy,queryXXBy,countXXBy, getXXBy后面跟屬性名稱:
User findByUserName(String userName);

也使用一些加一些關鍵字And、 Or
User findByUserNameOrEmail(String username, String email);

修改、刪除、統計也是類似語法
Long deleteById(Long id);
Long countByUserName(String userName)

基本上SQL體系中的關鍵詞都可以使用,例如:LIKE、 IgnoreCase、 OrderBy。
List<User> findByEmailLike(String email);
User findByUserNameIgnoreCase(String userName);
List<User> findByUserNameOrderByEmailDesc(String email);

具體的關鍵字,使用方法和生產成SQL如下表所示


Keyword
Sample
JPQL snippet




And
findByLastnameAndFirstname
… where x.lastname = ?1 and x.firstname = ?2


Or
findByLastnameOrFirstname
… where x.lastname = ?1 or x.firstname = ?2


Is,Equals
findByFirstnameIs,findByFirstnameEquals
… where x.firstname = ?1


Between
findByStartDateBetween
… where x.startDate between ?1 and ?2


LessThan
findByAgeLessThan
… where x.age < ?1


LessThanEqual
findByAgeLessThanEqual
… where x.age ⇐ ?1


GreaterThan
findByAgeGreaterThan
… where x.age > ?1


GreaterThanEqual
findByAgeGreaterThanEqual
… where x.age >= ?1


After
findByStartDateAfter
… where x.startDate > ?1


Before
findByStartDateBefore
… where x.startDate < ?1


IsNull
findByAgeIsNull
… where x.age is null


IsNotNull,NotNull
findByAge(Is)NotNull
… where x.age not null


Like
findByFirstnameLike
… where x.firstname like ?1


NotLike
findByFirstnameNotLike
… where x.firstname not like ?1


StartingWith
findByFirstnameStartingWith
… where x.firstname like ?1 (parameter bound with appended %)


EndingWith
findByFirstnameEndingWith
… where x.firstname like ?1 (parameter bound with prepended %)


Containing
findByFirstnameContaining
… where x.firstname like ?1 (parameter bound wrapped in %)


OrderBy
findByAgeOrderByLastnameDesc
… where x.age = ?1 order by x.lastname desc


Not
findByLastnameNot
… where x.lastname <> ?1


In
findByAgeIn(Collection ages)
… where x.age in ?1


NotIn
findByAgeNotIn(Collection age)
… where x.age not in ?1


TRUE
findByActiveTrue()
… where x.active = true


FALSE
findByActiveFalse()
… where x.active = false


IgnoreCase
findByFirstnameIgnoreCase
… where UPPER(x.firstame) = UPPER(?1)


復雜查詢
在實際的開發中我們需要用到分頁、刪選、連表等查詢的時候就需要特殊的方法或者自定義SQL
分頁查詢
分頁查詢在實際使用中非常普遍了,spring data jpa已經幫我們實現了分頁的功能,在查詢的方法中,需要傳入參數Pageable
,當查詢中有多個參數的時候Pageable建議做為最后一個參數傳入
Page<User> findALL(Pageable pageable);
Page<User> findByUserName(String userName,Pageable pageable);

Pageable 是spring封裝的分頁實現類,使用的時候需要傳入頁數、每頁條數和排序規則
@Test
public void testPageQuery() throws Exception {
int page=1,size=10;
Sort sort = new Sort(Direction.DESC, "id");
Pageable pageable = new PageRequest(page, size, sort);
userRepository.findALL(pageable);
userRepository.findByUserName("testName", pageable);
}

限制查詢
有時候我們只需要查詢前N個元素,或者支取前一個實體。
ser findFirstByOrderByLastnameAsc();
User findTopByOrderByAgeDesc();
Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);
List<User> findFirst10ByLastname(String lastname, Sort sort);
List<User> findTop10ByLastname(String lastname, Pageable pageable);

自定義SQL查詢
其實Spring data 覺大部分的SQL都可以根據方法名定義的方式來實現,但是由于某些原因我們想使用自定義的SQL來查詢,spring data也是完美支持的;在SQL的查詢方法上面使用@Query注解,如涉及到刪除和修改在需要加上@Modifying.也可以根據需要添加 @Transactional 對事物的支持,查詢超時的設置等
@Modifying
@Query("update User u set u.userName = ?1 where c.id = ?2")
int modifyByIdAndUserId(String userName, Long id);
@Transactional
@Modifying
@Query("delete from User where id = ?1")
void deleteByUserId(Long id);
@Transactional(timeout = 10)
@Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);

多表查詢
多表查詢在spring data jpa中有兩種實現方式,第一種是利用hibernate的級聯查詢來實現,第二種是創建一個結果集的接口來接收連表查詢后的結果,這里主要第二種方式。
首先需要定義一個結果集的接口類。
public interface HotelSummary {
City getCity();
String getName();
Double getAverageRating();
default Integer getAverageRatingRounded() {
return getAverageRating() == null ? null : (int) Math.round(getAverageRating());
}
}

查詢的方法返回類型設置為新創建的接口
@Query("select h.city as city, h.name as name, avg(r.rating) as averageRating "
- "from Hotel h left outer join h.reviews r where h.city = ?1 group by h")
Page<HotelSummary> findByCity(City city, Pageable pageable);
@Query("select h.name as name, avg(r.rating) as averageRating "
- "from Hotel h left outer join h.reviews r group by h")
Page<HotelSummary> findByCity(Pageable pageable);

使用
Page<HotelSummary> hotels = this.hotelRepository.findByCity(new PageRequest(0, 10, Direction.ASC, "name"));
for(HotelSummary summay:hotels){
System.out.println("Name" +summay.getName());
}

在運行中Spring會給接口(HotelSummary)自動生產一個代理類來接收返回的結果,代碼匯總使用getXX的形式來獲取


多數據源的支持
同源數據庫的多源支持
日常項目中因為使用的分布式開發模式,不同的服務有不同的數據源,常常需要在一個項目中使用多個數據源,因此需要配置sping data jpa對多數據源的使用,一般分一下為三步:
  • 1 配置多數據源

  • 2 不同源的實體類放入不同包路徑

  • 3 聲明不同的包路徑下使用不同的數據源、事務支持

  • 這里有一篇文章寫的很清楚:Spring Boot多數據源配置與使用
    異構數據庫多源支持
    比如我們的項目中,即需要對mysql的支持,也需要對mongodb的查詢等。
    實體類聲明@Entity 關系型數據庫支持類型、聲明@Document 為mongodb支持類型,不同的數據源使用不同的實體就可以了
    interface PersonRepository extends Repository<Person, Long> {
    …
    }
    @Entity
    public class Person {
    …
    }
    interface UserRepository extends Repository<User, Long> {
    …
    }
    @Document
    public class User {
    …
    }

    但是,如果User用戶既使用mysql也使用mongodb呢,也可以做混合使用
    interface JpaPersonRepository extends Repository<Person, Long> {
    …
    }
    interface MongoDBPersonRepository extends Repository<Person, Long> {
    …
    }
    @Entity
    @Document
    public class Person {
    …
    }

    也可以通過對不同的包路徑進行聲明,比如A包路徑下使用mysql,B包路徑下使用mongoDB
    @EnableJpaRepositories(basePackages = "com.neo.repositories.jpa")
    @EnableMongoRepositories(basePackages = "com.neo.repositories.mongo")
    interface Configuration { }

    其它
    使用枚舉
    使用枚舉的時候,我們希望數據庫中存儲的是枚舉對應的String類型,而不是枚舉的索引值,需要在屬性上面添加@Enumerated(EnumType.STRING) 注解
    @Enumerated(EnumType.STRING) 
    @Column(nullable = true)
    private UserType type;

    不需要和數據庫映射的屬性
    正常情況下我們在實體類上加入注解@Entity,就會讓實體類和表相關連如果其中某個屬性我們不需要和數據庫來關聯只是在展示的時候做計算,只需要加上@Transient屬性既可。
    @Transient
    private String userName;

    源碼案例
    這里有一個開源項目幾乎使用了這里介紹的所有標簽和布局,大家可以參考:
    cloudfavorites
    參考
    Spring Data JPA - Reference Documentation
    Spring Data JPA——參考文檔 中文版


    作者:純潔的微笑
    出處:http://www.ityouknow.com/
    版權所有,歡迎保留原文鏈接進行轉載:)
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(973)

    • 個人分類:生活學習
    ▲top
    • 3月 15 週三 201722:41
    • spring boot(二):web綜合開發


    文章出處
    上篇文章介紹了Spring boot初級教程:spring boot(一):入門篇,方便大家快速入門、了解實踐Spring boot特性;本篇文章接著上篇內容繼續為大家介紹spring boot的其它特性(有些未必是spring boot體系桟的功能,但是是spring特別推薦的一些開源技術本文也會介紹),對了這里只是一個大概的介紹,特別詳細的使用我們會在其它的文章中來展開說明。
    web開發
    spring boot web開發非常的簡單,其中包括常用的json輸出、filters、property、log等
    json 接口開發
    在以前的spring 開發的時候需要我們提供json接口的時候需要做那些配置呢

    1. 添加 jackjson 等相關jar包

    2. 配置spring controller掃描

    3. 對接的方法添加@ResponseBody


    就這樣我們會經常由于配置錯誤,導致406錯誤等等,spring boot如何做呢,只需要類添加 @RestController 即可,默認類中的方法都會以json的格式返回
    @RestController
    public class HelloWorldController {
    @RequestMapping("/getUser")
    public User getUser() {
    User user=new User();
    user.setUserName("小明");
    user.setPassWord("xxxx");
    return user;
    }
    }

    如果我們需要使用頁面開發只要使用@Controller ,下面會結合模板來說明
    自定義Filter
    我們常常在項目中會使用filters用于錄調用日志、排除有XSS威脅的字符、執行權限驗證等等。Spring Boot自動添加了OrderedCharacterEncodingFilter和HiddenHttpMethodFilter,并且我們可以自定義Filter。
    兩個步驟:

    1. 實現Filter接口,實現Filter方法

    2. 添加@Configurationz 注解,將自定義Filter加入過濾鏈


    好吧,直接上代碼
    @Configuration
    public class WebConfiguration {
    @Bean
    public RemoteIpFilter remoteIpFilter() {
    return new RemoteIpFilter();
    }
    @Bean
    public FilterRegistrationBean testFilterRegistration() {
    FilterRegistrationBean registration = new FilterRegistrationBean();
    registration.setFilter(new MyFilter());
    registration.addUrlPatterns("/*");
    registration.addInitParameter("paramName", "paramValue");
    registration.setName("MyFilter");
    registration.setOrder(1);
    return registration;
    }
    public class MyFilter implements Filter {
    @Override
    public void destroy() {
    // TODO Auto-generated method stub
    }
    @Override
    public void doFilter(ServletRequest srequest, ServletResponse sresponse, FilterChain filterChain)
    throws IOException, ServletException {
    // TODO Auto-generated method stub
    HttpServletRequest request = (HttpServletRequest) srequest;
    System.out.println("this is MyFilter,url :"+request.getRequestURI());
    filterChain.doFilter(srequest, sresponse);
    }
    @Override
    public void init(FilterConfig arg0) throws ServletException {
    // TODO Auto-generated method stub
    }
    }
    }

    自定義Property
    在web開發的過程中,我經常需要自定義一些配置文件,如何使用呢
    配置在application.properties中
    com.neo.title=純潔的微笑
    com.neo.description=分享生活和技術

    自定義配置類
    @Component
    public class NeoProperties {
    @Value("${com.neo.title}")
    private String title;
    @Value("${com.neo.description}")
    private String description;
    //省略getter settet方法
    }

    log配置
    配置輸出的地址和輸出級別
    logging.path=/user/local/log
    logging.level.com.favorites=DEBUG
    logging.level.org.springframework.web=INFO
    logging.level.org.hibernate=ERROR

    path為本機的log地址,logging.level 后面可以根據包路徑配置不同資源的log級別
    數據庫操作
    在這里我重點講述mysql、spring data jpa的使用,其中mysql 就不用說了大家很熟悉,jpa是利用Hibernate生成各種自動化的sql,如果只是簡單的增刪改查,基本上不用手寫了,spring內部已經幫大家封裝實現了。
    下面簡單介紹一下如何在spring boot中使用
    1、添加相jar包
     <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    </dependency>

    2、添加配置文件
    spring.datasource.url=jdbc:mysql://localhost:3306/test
    spring.datasource.username=root
    spring.datasource.password=root
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.jpa.properties.hibernate.hbm2ddl.auto=update
    spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
    spring.jpa.show-sql= true

    其實這個hibernate.hbm2ddl.auto參數的作用主要用于:自動創建|更新|驗證數據庫表結構,有四個值:

    1. create: 每次加載hibernate時都會刪除上一次的生成的表,然后根據你的model類再重新來生成新表,哪怕兩次沒有任何改變也要這樣執行,這就是導致數據庫表數據丟失的一個重要原因。

    2. create-drop :每次加載hibernate時根據model類生成表,但是sessionFactory一關閉,表就自動刪除。

    3. update:最常用的屬性,第一次加載hibernate時根據model類會自動建立起表的結構(前提是先建立好數據庫),以后加載hibernate時根據 model類自動更新表結構,即使表結構改變了但表中的行仍然存在不會刪除以前的行。要注意的是當部署到服務器后,表結構是不會被馬上建立起來的,是要等 應用第一次運行起來后才會。

    4. validate :每次加載hibernate時,驗證創建數據庫表結構,只會和數據庫中的表進行比較,不會創建新表,但是會插入新值。


    dialect 主要是指定生成表名的存儲引擎為InneoDB
    show-sql 是否打印出自動生產的SQL,方便調試的時候查看
    3、添加實體類和Dao
    @Entity
    public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue
    private Long id;
    @Column(nullable = false, unique = true)
    private String userName;
    @Column(nullable = false)
    private String passWord;
    @Column(nullable = false, unique = true)
    private String email;
    @Column(nullable = true, unique = true)
    private String nickName;
    @Column(nullable = false)
    private String regTime;
    //省略getter settet方法、構造方法
    }

    dao只要繼承JpaRepository類就可以,幾乎可以不用寫方法,還有一個特別有尿性的功能非常贊,就是可以根據方法名來自動的生產SQL,比如findByUserName 會自動生產一個以 userName 為參數的查詢方法,比如 findAlll 自動會查詢表里面的所有數據,比如自動分頁等等。。
    **Entity中不映射成列的字段得加@Transient 注解,不加注解也會映射成列**
    public interface UserRepository extends JpaRepository<User, Long> {
    User findByUserName(String userName);
    User findByUserNameOrEmail(String username, String email);

    4、測試
    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringApplicationConfiguration(Application.class)
    public class UserRepositoryTests {
    @Autowired
    private UserRepository userRepository;
    @Test
    public void test() throws Exception {
    Date date = new Date();
    DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
    String formattedDate = dateFormat.format(date);
    userRepository.save(new User("aa1", "aa@126.com", "aa", "aa123456",formattedDate));
    userRepository.save(new User("bb2", "bb@126.com", "bb", "bb123456",formattedDate));
    userRepository.save(new User("cc3", "cc@126.com", "cc", "cc123456",formattedDate));
    Assert.assertEquals(9, userRepository.findAll().size());
    Assert.assertEquals("bb", userRepository.findByUserNameOrEmail("bb", "cc@126.com").getNickName());
    userRepository.delete(userRepository.findByUserName("aa1"));
    }
    }

    當讓 spring data jpa 還有很多功能,比如封裝好的分頁,可以自己定義SQL,主從分離等等,這里就不詳細講了
    thymeleaf模板
    Spring boot 推薦使用來代替jsp,thymeleaf模板到底是什么來頭呢,讓spring大哥來推薦,下面我們來聊聊
    Thymeleaf 介紹
    Thymeleaf是一款用于渲染XML/XHTML/HTML5內容的模板引擎。類似JSP,Velocity,FreeMaker等,它也可以輕易的與Spring MVC等Web框架進行集成作為Web應用的模板引擎。與其它模板引擎相比,Thymeleaf最大的特點是能夠直接在瀏覽器中打開并正確顯示模板頁面,而不需要啟動整個Web應用。
    好了,你們說了我們已經習慣使用了什么 velocity,FreMaker,beetle之類的模版,那么到底好在哪里呢?
    比一比吧
    Thymeleaf是與眾不同的,因為它使用了自然的模板技術。這意味著Thymeleaf的模板語法并不會破壞文檔的結構,模板依舊是有效的XML文檔。模板還可以用作工作原型,Thymeleaf會在運行期替換掉靜態值。Velocity與FreeMarker則是連續的文本處理器。
    下面的代碼示例分別使用Velocity、FreeMarker與Thymeleaf打印出一條消息:
    Velocity: <p>$message</p>
    FreeMarker: <p>${message}</p>
    Thymeleaf: <p th:text="${message}">Hello World!</p>

    ** 注意,由于Thymeleaf使用了XML DOM解析器,因此它并不適合于處理大規模的XML文件。**
    URL
    URL在Web應用模板中占據著十分重要的地位,需要特別注意的是Thymeleaf對于URL的處理是通過語法@{...}來處理的。Thymeleaf支持絕對路徑URL:
    <a th:href="@{http://www.thymeleaf.org}">Thymeleaf</a>

    條件求值
    <a th:href="@{/login}" th:unless=${session.user != null}>Login</a>

    for循環
    <tr th:each="prod : ${prods}">
    <td th:text="${prod.name}">Onions</td>
    <td th:text="${prod.price}">2.41</td>
    <td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
    </tr>

    就列出這幾個吧
    頁面即原型
    在Web開發過程中一個繞不開的話題就是前端工程師與后端工程師的寫作,在傳統Java Web開發過程中,前端工程師和后端工程師一樣,也需要安裝一套完整的開發環境,然后各類Java IDE中修改模板、靜態資源文件,啟動/重啟/重新加載應用服務器,刷新頁面查看最終效果。
    但實際上前端工程師的職責更多應該關注于頁面本身而非后端,使用JSP,Velocity等傳統的Java模板引擎很難做到這一點,因為它們必須在應用服務器中渲染完成后才能在瀏覽器中看到結果,而Thymeleaf從根本上顛覆了這一過程,通過屬性進行模板渲染不會引入任何新的瀏覽器不能識別的標簽,例如JSP中的
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(62)

    • 個人分類:生活學習
    ▲top
    • 3月 15 週三 201722:41
    • linux定時備份mysql并同步到其它服務器


    文章出處
    數據在任何一家公司里面都是最核心的資產,定期備份則是為了保證數據庫出現問題的時候能夠及時回滾到最近的備份點,將損失縮小到最小
    這篇文章將會兩部分來說明:1、mysql的定期備份;2、同步到其它服務器
    mysql 備份
    備份還原某個數據庫
    備份還原
    # 導出數據庫
    /usr/bin/mysqldump -u root -ppwd database > database20160929.sql
    # 導入數據庫
    mysql -u root -p database < database20160929.sql

    備份到壓縮文件從壓縮文件導入
    #備份到壓縮文件
    /usr/bin/mysqldump -u root -ppwd database | gzip > database20160929.sql.gz
    #從壓縮文件導入
    gzip < database20160929.sql.gz | mysql -u root -p database

    crontab定時備份
    1、創建備份目錄
    # root 用戶,創建備份目錄
    mkdir -p /bak/mysqlbak
    cd /bak/mysqldata

    2、編寫運行腳本
    vi /usr/sbin/bakmysql.sh
    腳本代碼:
    #!/bin/bash
    # Name:bakmysql.sh
    # This is a ShellScript For Auto DB Backup and Delete old Backup
    #
    backupdir=/bak/mysqlbak
    time=` date +%Y%m%d%H `
    mysql_bin_dir/mysqldump -u root -ppwd database | gzip > $backupdir/database$time.sql.gz
    #
    find $backupdir -name "name_*.sql.gz" -type f -mtime +7 -exec rm {} ; > /dev/null 2>&1
    #

    腳本說明:
  • backupdir mysql備份地址

  • root mysql用戶名

  • pwd mysql密碼

  • database 數據庫名

  • mysql_bin_dir mysql的bin路徑;

  • time=` date +%Y%m%d%H `也可以寫為time="$(date +"%Y%m%d$H")"其中`符號是TAB鍵上面的符號,不是ENTER左邊的'符號,還有date后要有一個空格。

  • type f 表示查找普通類型的文件,f表示普通文件。

  • mtime +7 按照文件的更改時間來查找文件,+5表示文件更改時間距現在7天以前;如果是 -mmin +5 表示文件更改時間距現在5分鐘以前。

  • exec rm {} \ 表示執行一段shell命令,exec選項后面跟隨著所要執行的命令或腳本,然后是一對兒{},一個空格和一個\,最后是一個分號。

  • /dev/null 2>&1 把標準出錯重定向到標準輸出,然后扔到/DEV/NULL下面去。通俗的說,就是把所有標準輸出和標準出錯都扔到垃圾桶里面;其中的& 表示讓該命令在后臺執行。

  • 3、為腳本添加執行權限
    # chmod +x /usr/sbin/bakmysql.sh
    4、設置crontab定時執行
    vi /etc/crontab
    #在最后一行中加入:
    00 3 * * * root /usr/sbin/bakmysql.sh
    #表示每天3點00分執行備份

    注:crontab配置文件格式如下:
    分 時 日 月 周  命令


    5、重啟crontab
    /etc/rc.d/init.d/crond restart
    這樣就完了定時備份并清理前7天的備份數據
    同步到其它服務器
    這里使用Linux同步文件工具rsync+inotify來進行文件的同步
    rsync
    rsync是類unix系統下的數據鏡像備份工具——remote sync。一款快速增量備份工具 Remote Sync,遠程同步 支持本地復制,或者與其他SSH、rsync主機同步
    用法
    rsync src dest
    這是最簡單的用法,表示同步src,dest文件。(即,執行之后,dest的文件與src的相同,以src的為準)
    常用選項

    • -a: 等價于-rlptgoD,歸檔式

    • -r: 遞歸

    • -l: 復制軟件鏈接

    • -p: 保留權限信息

    • -t: 將src的修改時間,同步到dest

    • -g: 同步組信息(group)

    • -o: 同步擁有者信息(own)

    • -D: 保持字符與塊設備文件

    • -z: 啟用壓縮傳輸

    • -–delete:如果src沒有此文件,那么dest也不能有,即在dest刪除src里沒有的文件。(如果你使用這個選項,就必須搭配-r選項一起)


    ## 將本地/bak/mysqlbak/文件同步到 遠程服務器 /bak/mysql/bak 目錄下面 排除 mysqlbak/index目錄 通過ssh端口
    rsync -vzacu /bak/mysqlbak/ root@192.168.53.86:/bak/mysqlbak --exclude "mysqlbak/index" -e "ssh -p 22"
    # 將遠程目錄 /bak/mysqlbak下的文件同步到本地 /bak/mysqlbak/目錄下
    rsync -vzrtopg --progress --delete root@192.168.53.85:/bak/mysqlbak /bak

    啟用rsync服務器端同步遠程文件
    rsycn的服務端為服務器的文件接收端,rsycn的客戶端為服務器的文件推動端。
    rsycn的服務端/文件接收端配置
    服務端需要開啟rsyncd服務
    添加配置文件rsyncd.conf
    vi /etc/rsyncd.conf
    #以下是全局配置
    log file = /var/log/rsyncd.log
    pid file = /var/run/rsyncd.pid
    lock file = /var/lock/rsyncd
    [mysqlbak] #模塊名,在源服務器指定這個名字
    comment = sync rsync/home #描述信息
    path = /bak/mysqlbak #備份目錄
    use chroot=no #不使用chroot,不用root權限
    read only = no #設置本地備份目錄為讀寫權限
    uid=root
    gid=root
    max connections=10 #客戶端最大連接數
    auth users = root #指定數據同步用戶
    secrets file = /etc/rsyncd.pass #指定數據同步用戶信息文件
    hosts allow=192.168.53.0/85 #允許連接的客戶端
    ignore errors = yes #忽略出現I/O錯誤
    timeout = 600

    創建認證文件
    vi /etc/rsyncd.pass
    ##代碼
    root:root #格式是用戶名:密碼
    #屬主要有權限讀這個文件,否則會報沒權限
    chmod 600 /etc/rsyncd.pass

    修改/etc/xinetd.d/rsync文件,disable 改為 no
    service rsync
    {
    disable = no
    socket_type = stream
    wait = no
    user = root
    server = /usr/bin/rsync
    server_args = --daemon
    log_on_failure += USERID
    }

    啟動服務端
    rsync --daemon --config=/etc/rsyncd.conf
    rsycn的客戶端/文件發送端配置
    客戶端配置簡單 只需要配置密碼既可
    vi /etc/rsync_client.pwd
    ##代碼
    root #只需要填寫rsync服務的密碼
    #屬主要有權限讀這個文件,否則會報沒權限
    chmod 600 /etc/rsync_client.pwd

    客戶端同步測試
    /usr/bin/rsync -auvrtzopgP --progress --password-file=/etc/rsync_client.pwd /bak/mysqlbak/ root@192.168.53.86::mysqlbak

    rsync只是一次性同步,如果需要實時同步就需要引入另一個工具了


    inotify
    Inotify 是一種強大的、細粒度的、異步的文件系統事件監控機制,linux內核從2.6.13起,加入了Inotify支持,通過Inotify可以監控文件系統中添加、刪除,修改、移動等各種細微事件,利用這個內核接口,第三方軟件就可以監控文件系統下文件的各種變化情況,而inotify-tools就是這樣的一個第三方軟件。

    Inotify只需要要按照部署在同步的客戶端,當監控的文件有變化觸動 rsync腳本來同步


    安裝
    yum install inotify-tools
    配置監控的文件路徑
    vi /etc/inotify_exclude.lst
    #代碼
    /bak/mysqlbak #監控目錄
    @/bak/log #排除監控目錄

    rsync排除監控文件目錄
    vi /etc/rsyncd.d/rsync_exclude.lst
    #代碼
    src/*.html*
    src/js/
    src/2014/20140[1-9]/

    客戶端同步到遠程的腳本rsync.sh
    #rsync auto sync script with inotify
    #variables
    current_date=$(date +%Y%m%d_%H%M%S)
    source_path=/bak/mysqlbak/
    log_file=/var/log/rsync_client.log
    #rsync
    rsync_server=192.168.53.86
    rsync_user=root
    rsync_pwd=/etc/rsync_client.pwd
    rsync_module=mysqlbak
    INOTIFY_EXCLUDE='(.*/*\.log|.*/*\.swp)$|^/tmp/src/mail/(2014|20.*/.*che.*)'
    RSYNC_EXCLUDE='/bak/rsync_exclude.lst'
    #rsync client pwd check
    if [ ! -e ${rsync_pwd} ];then
    echo -e "rsync client passwod file ${rsync_pwd} does not exist!"
    exit 0
    fi
    #inotify_function
    inotify_fun(){
    /usr/bin/inotifywait -mrq --timefmt '%Y/%m/%d-%H:%M:%S' --format '%T %w %f' \
    --exclude ${INOTIFY_EXCLUDE} -e modify,delete,create,move,attrib ${source_path} \
    | while read file
    do
    /usr/bin/rsync -auvrtzopgP --exclude-from=${RSYNC_EXCLUDE} --progress --bwlimit=200 --password-file=${rsync_pwd} ${source_path} ${rsync_user}@${rsync_server}::${rsync_module}
    done
    }
    #inotify log
    inotify_fun >> ${log_file} 2>&1 &

    給腳本執行權限,執行后就可以了
    chmod 777 rsync.sh
    ./rsync.sh

    參考:
    Linux下同步工具inotify+rsync使用詳解


    作者:純潔的微笑
    出處:http://www.ityouknow.com/
    版權所有,歡迎保留原文鏈接進行轉載 :)
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(41)

    • 個人分類:生活學習
    ▲top
    • 3月 15 週三 201722:41
    • 程序員該用哪種姿勢來理財


    文章出處
    其實一直想寫一篇文章名字都想好了,叫做“程序員該不該理財?”。后來想了想,該不該這個就不用想了,必須要理財!那么市面上那么多理財的方式對于我們屌絲的程序員該如何選擇呢?其實我也是那種土的掉咋的那種類型,以前幾乎沒有想過神馬理財的,一來呢畢業的時候工資全都不夠花的還理個毛線,二來總是感覺理財好像都是有錢人搞的東西;后來偶然進入了互聯網金融行業,呆了幾年,慢慢也接觸了很多理財方式,但也還是一個門外漢,此文就是和大家一起聊聊我們程序員該如何去理財?算是拋磚引玉,歡迎拍磚。
    純潔的微笑原創 轉載請注明出處 http://www.cnblogs.com/ityouknow/p/5772248.html
    我的理財經歷
    先聊聊我的理財經歷,我的理財大概也是從畢業三年之后才慢慢開始的,對了也就是從余額寶開始,后來在第三方支付、互聯網金融公司工作,對理財的種類了解慢慢多了起來,互聯網金融也就是P2P或者金融公司產品各種變種(其實也是債權類產品的進一步封裝),有活期產品、封閉期的固定收益產品(日、月、年類的固定收益);買了股票(先是A股,后來美股),在了解了基金(指數基金、債券基金、股票基金等等),后來也看了黃金和期貨(了解較少)、保險接觸最少。
    一路慢慢走來,理財的這種想法和認識也是在不斷的發展變化,不認識、不了解、不認同的一些偏見也在慢慢的消失,可以以更理性的角度去看待投資理財的這件事情,理財真的是我們每一個人都應該好好的學習的事情,如何讓你辛辛苦苦的積蓄可以跑贏通貨膨脹,不隨著時間推移我們的資產不斷縮水;但是在工作中常常發現我們的程序員對于理財目前來講大多都還是比較保守,常常是全部都銀行或者全部寶寶類產品,更有激進者全都投入股市,有一年損失十幾萬的。下面分幾個階段來聊聊我對理財的幾個認識:
    寶寶時代
    說起了理財或者第三方支付,總是不能避開一家偉大的公司-支付寶,支付寶一直在引領、教育著我們這一代人對于理財的認識;我的理財起點就是從余額寶開始的,清晰的記得13年6月余額寶出來的時候,大家都感覺到稀奇或者不了解(當時仍然有很多人認為還是把錢放到銀行保險,哪怕余額寶也是!),記得當初剛開始余額寶轉進去了100元,每天看著它給帶來的幾分錢收益都很滿足,然后就一發不扣收拾,幾乎是前腳收到發工資的短信,下一分鐘錢就同步到了余額寶里面,曾經有一段時間中國鬧錢荒,導致余額寶的最高收益高達6.76;
    不過后來由于這塊的蛋糕臺大了,各大銀行也都著急出了很多的政策來限制:第一步,開限額,導致大額資金無法進入;第二步,自己干,很多銀行自己也推出了資金的貨幣基金理財產品和余額寶來競爭,理財通也橫空出世,理財通搞了一個同卡進出的理念比較好,很大程度上對資金安全起了很大的作用。
    互聯網金融
    2014年算是互聯網金融的元年,其實互聯網金融在很早的時候就被引入了國內,之前一直是不溫不火的發展著,突然到了2014年隨著資本的大量進入催化了互聯網金融的大發展。現在的互聯網金融主要分為大的兩個部分:p2p和眾籌,p2p在中國發展進行非常多的變種,現在主要的產品有活期債權、封裝成月或者年的理財產品,然后后面去打包,從債權方面又分為,企業和個人。我也是在2014年由于工作原因接觸到了p2p,小做嘗試了之后,發現完爆余額寶,幾乎又是全部積蓄投入到p2p里面,當初算了一筆賬,按照年化12的標的來計算的話,投入10萬,一年的收益就是1.2萬,投資1000萬,那么每年不用工作就是120萬!,輕輕松松的年收入破百萬!對了沒有一點稅!!
    那時候各家平臺又是送蘋果手機、又是送電腦的各種活動玩的不亦樂乎,后來到了15年跑路了很多平臺,慢慢的才把很大的一部分撤了出來。眾籌也是在中國玩出了很多的花樣,主要還是分為產品眾籌和股權眾籌,產品眾籌主要是以高科技產品為主,但是現在很多新品發布會也搞上去了;股權眾籌也就是拿出自己的錢去投資一些比較看好的小公司來占一部分原始股權,一般股權眾籌都有一定的門檻,沒有資金百萬級別以上基本上不用參與了,風險也非常大不是咱這小市民可以玩的。
    股票
    我是在第一次股災快結束的時候進入的,15年股市正火爆的時候公司有很多的同事整天都在關注著股票,什么過了3000點了,這回進去就是炮灰了,然后大盤到了4000點,有同事又說,人民日報都刊登了文章,4000點只是一個起點,好吧,他們最后的結局都是什么,我就不說了大家也猜的到,那時候我們部門幾乎有一半的程序員多多少少都在在A股開了戶,活動的時候也是在討論著各種的股票。
    到了6月份以后我突然有了點時間,也就特別好奇股市為啥有這么大的吸引力,也試探性的在網上開了戶,在網上找了費率最便宜的那種,好多同事都是在模擬炒股的軟件上面模擬的先玩上一段時候再進入市場,但是我覺得模擬因為沒有真正的資金在上面,感覺不到任何的刺激。于是乎剛開始搞了1000元的資金去試探。清楚的記得買的第一只股票是“蘇寧云商”,然后迫不及待的每天看著它漲了還是跌了樂此不疲,買了沒有多久“蘇寧云商”就停牌了,發公告說阿里投資,重大利好!好多人都說股市新手的運氣都會比較好,先給你一點甜頭,讓你先陷進去,然后慢慢在和你玩,后來“蘇寧云商”開盤后連續三個漲停,賺了幾百塊錢。
    我立刻對股市產生了極大的興趣,大家是不是又準備看一個A股小散被收割的故事:) 于是乎,追漲殺跌、專門看股票技術指標(成交量、KDJ、MACD ...)、請教一些玩股票的朋友推薦股票,分析股票。專門組建了一個討論組,把喜歡炒股的幾個IT的朋友都拉進去,大家討論每天的行情,那是一個熱鬧!慢慢的發現很多科技股票買不了才發現創業板是需要專門去線下開通,好吧,迫不及待就去開通了創業板。短短的6個月買了很多股票,樂視、掌趣科技、東方財富、衛寧健康、華裔兄弟、萬達院線、信息發展。。。。。多到我也不清楚到底買了多少,全部短線交易!資金也從最初的1000一直增加到最高50000,經歷了股災2.0、3.0,也經歷了創業板最低的1800點、10月份的超級大反彈、今年的熔斷。認識的兩個朋友中,有一個在牛市的時候曾經一周每天盈利1萬(這樣還有什么心情上班),有一個在股災中還么賠多少但是熔斷沒有躲過去,搭進去近一年的工資。
    作為一個IT男,中國最優秀的互聯網幾乎都在美國上市,所以就一直了解如何去買美股,那時候“宜人貸”剛上納斯達克破發了,"lending club 簡稱LC" 也跌到12美元左右,覺得是個機會。剛好積木出了一款產品叫做積木股票,就迫不及待的注冊、開通海外匯款。進去之后就買了LC ,結果LC沒多久就跌到8美元、7、6 ...。失望之極,剛退出沒多久LC又出黑天鵝時間 ,直接從7左右跌到最低3.44美元!美股由于沒有漲跌幅度的限制比A股要刺激很多,經常看到某一個股票一天漲40%、50%,但跌的時候也一樣經常一下子一半市值就沒了,我在美股的虧損幾乎都來自LC。宜人貸是讓我非常震撼的一只股票,因為從開盤一直跌到3美元左右,然后開始上升到現在達30美元左右,沒有抓住非常可惜。現在手里拿的都是一些中概念股,京東、58、獵豹等。
    基金
    一個人的精力總是有限,整天看股票真的很累還影響工作、有時候甚至影響心情還不一定賺錢。如何想讓牛逼的人來替我們理財,這時候也就慢慢的了解到了基金,特別是在關注了微信公共賬號的“股社區”學了很多的知識,目前也是剛剛了解一些。基金我了解主要是這幾種:債卷基金,主要是買國家的債卷或者國企類型的公司債卷為主,風險度比較低,收益率也偏低一些,我目前就是定投的這類;股票基金,也就是找一個牛逼的基金經理幫我們炒股,盈利了大家分錢這種模式,風險也很高,也比較依賴于基金經理的個人水平。大盤類的基金,比如ETF300 之類,就是買主板最牛逼的股票各買一點,只要大盤漲,我們收益就會漲,大盤跌,我們就會虧損這種,短期看收益很難確定,長期來看肯定收益為正;也有一部分混合基金就是股票和債卷都買一些。
    黃金
    2016年初的時候,各種報道黃金跌破1000美元就是底部,那時候是1100美元左右吧,感覺差不多了,就買了交通銀行黃金延期(T+D)買了不到一萬元,沒幾天虧損了一點就出來了沒有堅持,如果堅持到現在那也賺了一些;有時候你想到和做到完全是兩種情形。現在如果想投資黃金的話,直接買螞蟻聚寶的“存金寶”,關鍵方便快捷。
    我的投資經驗與教訓
    結合我這三年多的投資理財教訓,談一些對投資的看法。
    銀行存款
    一直流行著一句話,窮人往銀行里面存錢,富人從銀行中貸款,可以很大程度上反應中國情況。如果你把積蓄都放到銀行里面躺著,結合通貨膨脹來講,你就是在虧錢!而且銀行的服務超級爛,辦業務超級慢,因此建議銀行卡里面一分錢也不要放!
    寶寶類產品
    可以把平時需要緊急用的錢和零花的錢都可以放到這里面,既可以享受一定的收益性,也可以靈活的存取、消費,建議以大平臺余額寶、理財通為主,其它類的謹慎選擇。
    互聯網金融
    平臺真的重要! 平臺真的重要!! 平臺真的重要!!! 重要的事情說三遍,如果選擇不好平臺就是0和1的事情,投資的平臺跑路了就一分錢都沒有了,筆者就投資了一個跑路的公司e租寶和一個在跑路之前投資過的公司。我們經常說,你貪戀的是人家的利息 ,人家貪戀的是你的本金。 但回過頭來看其實大多數跑路的公司都是騙子公司,幾乎沒有什么正經的互聯網金融公司,只是打著互聯網金融的旗號來行騙而已。P2P真的風險很高嗎,其實筆者看來只要選擇好平臺,應該還是非常好的一種理財方式。那怎么選擇平臺呢,盡量選擇評級靠前、國企或者上市公司背景的企業。
    股市和基金
    股市是一個學問很深的東西,有人窮盡一生也不能領悟,主要看性格、價值觀、人性的把握。大家要以我為戒,禁忌追漲殺跌、頻繁買賣,要堅持價值投資,持續持用,追求長遠的收益。股市也是一個風險度很高的投資,大家需要根據自己的風險偏好來選擇投資,也可以適當的選擇合適的基金產品來投資,一般股票配置比率應該和年齡成反比,越年輕就可以多占比你投資的一部分,最重要的是不要讓股票影響了我們正常的生活和工作!一直想找一個既可以買A股、港股和美股的產品,一直沒有發現很可惜。對于股市,要敬畏它、尊重它、理解它。
    比如程序員來講最酷的方法就是用 Python 寫一些程序進行量化交易或者分析股票相關內容,我這里也給大家推薦一個:股票分析(一):常見的技術指標雪球
    黃金和保險
    和平時期買股票,戰亂期間買黃金,這個要看每個的理解了,我了解也不是很多;保險是我了解最少的一部分了,總感覺我們這么年輕考慮保險干啥呢,但是這種保險的意識也需要慢慢的養成。
    買房
    好多人評論說沒有提到買房,是因為對于這個買房還真不太懂,但我感覺拐點也快到了,一線城市的房價很難說,但是三四線投資房產的必要性真的不太大了,而且買房建議一定買核心地段或者位置環境偏好的小區,貴一點不要緊,方便以后轉手。
    資產配置
    我目前的資金配置是,寶寶類產品1/4、p2p投資1/4、a股+美股3/8、基金1/8;大家可以根據各自風險承受度來選擇自己的資產配比。
    最后
    理財是我們每一個人必須要關注的事情,那怕我們現在并沒有多少錢,經常看到一個廣告說,投資是你人生最后的一個事業,隨著年齡的增長投資理財對我們越來越重要。投資也是一件謹慎、嚴肅的事情畢竟關系著我們辛苦賺的血汗錢。
    最后的最后
    對于我們,投資自己更重要!
    投資有風險,理財需謹慎 !
    好多人私信想一起交流,我就建了一個QQ群,有興趣的入群交流:308719523 暗號:程序員
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(23)

    • 個人分類:生活學習
    ▲top
    • 3月 15 週三 201722:41
    • spring boot(四):thymeleaf使用詳解


    文章出處
    在上篇文章springboot(二):web綜合開發中簡單介紹了一下thymeleaf,這篇文章將更加全面詳細的介紹thymeleaf的使用。thymeleaf 是新一代的模板引擎,在spring4.0中推薦使用thymeleaf來做前端模版引擎。
    thymeleaf介紹
    簡單說, Thymeleaf 是一個跟 Velocity、FreeMarker 類似的模板引擎,它可以完全替代 JSP 。相較與其他的模板引擎,它有如下三個極吸引人的特點:
  • 1.Thymeleaf 在有網絡和無網絡的環境下皆可運行,即它可以讓美工在瀏覽器查看頁面的靜態效果,也可以讓程序員在服務器查看帶數據的動態頁面效果。這是由于它支持 html 原型,然后在 html 標簽里增加額外的屬性來達到模板+數據的展示方式。瀏覽器解釋 html 時會忽略未定義的標簽屬性,所以 thymeleaf 的模板可以靜態地運行;當有數據返回到頁面時,Thymeleaf 標簽會動態地替換掉靜態內容,使頁面動態顯示。


  • 2.Thymeleaf 開箱即用的特性。它提供標準和spring標準兩種方言,可以直接套用模板實現JSTL、 OGNL表達式效果,避免每天套模板、該jstl、改標簽的困擾。同時開發人員也可以擴展和創建自定義的方言。


  • 3.Thymeleaf 提供spring標準方言和一個與 SpringMVC 完美集成的可選模塊,可以快速的實現表單綁定、屬性編輯器、國際化等功能。


  • 標準表達式語法
    它們分為四類:
  • 1.變量表達式

  • 2.選擇或星號表達式

  • 3.文字國際化表達式

  • 4.URL表達式

  • 變量表達式
    變量表達式即OGNL表達式或Spring EL表達式(在Spring術語中也叫model attributes)。如下所示:
    ${session.user.name}
    它們將以HTML標簽的一個屬性來表示:
    <span th:text="${book.author.name}"> 
    <li th:each="book : ${books}">

    選擇(星號)表達式
    選擇表達式很像變量表達式,不過它們用一個預先選擇的對象來代替上下文變量容器(map)來執行,如下:
    *{customer.name}
    被指定的object由th:object屬性定義:
     <div th:object="${book}"> 
    ...
    <span th:text="*{title}">...</span>
    ...
    </div>

    文字國際化表達式
    文字國際化表達式允許我們從一個外部文件獲取區域文字信息(.properties),用Key索引Value,還可以提供一組參數(可選).
     #{main.title} 
    #{message.entrycreated(${entryId})}

    可以在模板文件中找到這樣的表達式代碼:
     <table> 
    ...
    <th th:text="#{header.address.city}">...</th>
    <th th:text="#{header.address.country}">...</th>
    ...
    </table>

    URL表達式
    URL表達式指的是把一個有用的上下文或回話信息添加到URL,這個過程經常被叫做URL重寫。
    @{/order/list}
    URL還可以設置參數:
    @{/order/details(id=${orderId})}
    相對路徑:
    @{../documents/report}
    讓我們看這些表達式:
     <form th:action="@{/createOrder}"> 
    <a href="main.html" th:href="@{/main}">

    變量表達式和星號表達有什么區別嗎?
    如果不考慮上下文的情況下,兩者沒有區別;星號語法評估在選定對象上表達,而不是整個上下文
    什么是選定對象?就是父標簽的值,如下:
     <div th:object="${session.user}">
    <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
    <p>Surname: <span th:text="*{lastName}">Pepper</span>.</p>
    <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
    </div>

    這是完全等價于:
     <div th:object="${session.user}">
    <p>Name: <span th:text="${session.user.firstName}">Sebastian</span>.</p>
    <p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p>
    <p>Nationality: <span th:text="${session.user.nationality}">Saturn</span>.</p>
    </div>

    當然,美元符號和星號語法可以混合使用:
     <div th:object="${session.user}">
    <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
    <p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p>
    <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
    </div>

    表達式支持的語法
    字面(Literals)
  • 文本文字(Text literals): 'one text', 'Another one!',…

  • 數字文本(Number literals): 0, 34, 3.0, 12.3,…

  • 布爾文本(Boolean literals): true, false

  • 空(Null literal): null

  • 文字標記(Literal tokens): one, sometext, main,…

  • 文本操作(Text operations)
  • 字符串連接(String concatenation): +

  • 文本替換(Literal substitutions): |The name is ${name}|

  • 算術運算(Arithmetic operations)
  • 二元運算符(Binary operators): +, -, *, /, %

  • 減號(單目運算符)Minus sign (unary operator): -

  • 布爾操作(Boolean operations)
  • 二元運算符(Binary operators):and, or

  • 布爾否定(一元運算符)Boolean negation (unary operator):!, not

  • 比較和等價(Comparisons and equality)
  • 比較(Comparators): >, <, >=, <= (gt, lt, ge, le)

  • 等值運算符(Equality operators):==, != (eq, ne)

  • 條件運算符(Conditional operators)
  • If-then: (if) ? (then)

  • If-then-else: (if) ? (then) : (else)

  • Default: (value) ?: (defaultvalue)

  • 所有這些特征可以被組合并嵌套:
    'User is of type ' + (${user.isAdmin()} ? 'Administrator' : (${user.type} ?: 'Unknown'))

    常用th標簽都有那些?


    關鍵字
    功能介紹
    案例




    th:id
    替換id
    <input th:id="'xxx' + ${collect.id}"/>


    th:text
    文本替換
    <p th:text="${collect.description}">description</p>


    th:utext
    支持html的文本替換
    <p th:utext="${htmlcontent}">conten</p>


    th:object
    替換對象
    <div th:object="${session.user}">


    th:value
    屬性賦值
    <input th:value="${user.name}" />


    th:with
    變量賦值運算
    <div th:with="isEven=${prodStat.count}%2==0"></div>


    th:style
    設置樣式
    th:style="'display:' + @{(${sitrue} ? 'none' : 'inline-block')} + ''"


    th:onclick
    點擊事件
    th:onclick="'getCollect()'"


    th:each
    屬性賦值
    tr th:each="user,userStat:${users}">


    th:if
    判斷條件
    <a th:if="${userId == collect.userId}" >


    th:unless
    和th:if判斷相反
    <a th:href="@{/login}" th:unless=${session.user != null}>Login</a>


    th:href
    鏈接地址
    <a th:href="@{/login}" th:unless=${session.user != null}>Login</a> />


    th:switch
    多路選擇 配合th:case 使用
    <div th:switch="${user.role}">


    th:case
    th:switch的一個分支
    <p th:case="'admin'">User is an administrator</p>


    th:fragment
    布局標簽,定義一個代碼片段,方便其它地方引用
    <div th:fragment="alert">


    th:include
    布局標簽,替換內容到引入的文件
    <head th:include="layout :: htmlhead" th:with="title='xx'"></head> />


    th:replace
    布局標簽,替換整個標簽到引入的文件
    <div th:replace="fragments/header :: title"></div>


    th:selected
    selected選擇框 選中
    th:selected="(${xxx.id} == ${configObj.dd})"


    th:src
    圖片類地址引入
    <img class="img-responsive" alt="App Logo" th:src="@{/img/logo.png}" />


    th:inline
    定義js腳本可以使用變量
    <script type="text/javascript" th:inline="javascript">


    th:action
    表單提交的地址
    <form action="subscribe.html" th:action="@{/subscribe}">


    th:remove
    刪除某個屬性
    <tr th:remove="all"> 1.all:刪除包含標簽和所有的孩子。2.body:不包含標記刪除,但刪除其所有的孩子。3.tag:包含標記的刪除,但不刪除它的孩子。4.all-but-first:刪除所有包含標簽的孩子,除了第一個。5.none:什么也不做。這個值是有用的動態評估。


    th:attr
    設置標簽屬性,多個屬性可以用逗號分隔
    比如 th:attr="src=@{/image/aa.jpg},title=#{logo}",此標簽不太優雅,一般用的比較少。


    還有非常多的標簽,這里只列出最常用的幾個,由于一個標簽內可以包含多個th:x屬性,其生效的優先級順序為:
    include,each,if/unless/switch/case,with,attr/attrprepend/attrappend,value/href,src ,etc,text/utext,fragment,remove。
    幾種常用的使用方法
    1、賦值、字符串拼接
     <p th:text="${collect.description}">description</p>
    <span th:text="'Welcome to our application, ' + ${user.name} + '!'">

    字符串拼接還有另外一種簡潔的寫法
    <span th:text="|Welcome to our application, ${user.name}!|">

    2、條件判斷 If/Unless
    Thymeleaf中使用th:if和th:unless屬性進行條件判斷,下面的例子中,<a>標簽只有在th:if中條件成立時才顯示:
    <a th:if="${myself=='yes'}" > </i> </a>
    <a th:unless=${session.user != null} th:href="@{/login}" >Login</a>

    th:unless于th:if恰好相反,只有表達式中的條件不成立,才會顯示其內容。
    也可以使用 (if) ? (then) : (else) 這種語法來判斷顯示的內容
    3、for 循環
     <tr th:each="collect,iterStat : ${collects}"> 
    <th scope="row" th:text="${collect.id}">1</th>
    <td >
    <img th:src="${collect.webLogo}"/>
    </td>
    <td th:text="${collect.url}">Mark</td>
    <td th:text="${collect.title}">Otto</td>
    <td th:text="${collect.description}">@mdo</td>
    <td th:text="${terStat.index}">index</td>
    </tr>

    iterStat稱作狀態變量,屬性有:
  • index:當前迭代對象的index(從0開始計算)

  • count: 當前迭代對象的index(從1開始計算)

  • size:被迭代對象的大小

  • current:當前迭代變量

  • even/odd:布爾值,當前循環是否是偶數/奇數(從0開始計算)

  • first:布爾值,當前循環是否是第一個

  • last:布爾值,當前循環是否是最后一個

  • 4、URL
    URL在Web應用模板中占據著十分重要的地位,需要特別注意的是Thymeleaf對于URL的處理是通過語法@{...}來處理的。
    如果需要Thymeleaf對URL進行渲染,那么務必使用th:href,th:src等屬性,下面是一個例子
    <!-- Will produce 'http://localhost:8080/standard/unread' (plus rewriting) -->
    <a th:href="@{/standard/{type}(type=${type})}">view</a>
    <!-- Will produce '/gtvg/order/3/details' (plus rewriting) -->
    <a href="details.html" th:href="@{/order/{orderId}/details(orderId=${o.id})}">view</a>

    設置背景
    <div th:style="'background:url(' + @{/<path-to-image>} + ');'"></div>

    根據屬性值改變背景
     <div class="media-object resource-card-image" th:style="'background:url(' + @{(${collect.webLogo}=='' ? 'img/favicon.png' : ${collect.webLogo})} + ')'" ></div>

    幾點說明:
  • 上例中URL最后的(orderId=${o.id}) 表示將括號內的內容作為URL參數處理,該語法避免使用字符串拼接,大大提高了可讀性

  • @{...}表達式中可以通過{orderId}訪問Context中的orderId變量

  • @{/order}是Context相關的相對路徑,在渲染時會自動添加上當前Web應用的Context名字,假設context名字為app,那么結果應該是/app/order

  • 5、內聯js
    內聯文本:[[...]]內聯文本的表示方式,使用時,必須先用th:inline="text/javascript/none"激活,th:inline可以在父級標簽內使用,甚至作為body的標簽。內聯文本盡管比th:text的代碼少,不利于原型顯示。
    <script th:inline="javascript">
    /*<![CDATA[*/
    ...
    var username = /*[[${sesion.user.name}]]*/ 'Sebastian';
    var size = /*[[${size}]]*/ 0;
    ...
    /*]]>*/
    </script>

    js附加代碼:
    /*[+
    var msg = 'This is a working application';
    +]*/

    js移除代碼:
    /*[- */
    var msg = 'This is a non-working template';
    /* -]*/

    6、內嵌變量
    為了模板更加易用,Thymeleaf還提供了一系列Utility對象(內置于Context中),可以通過#直接訪問:
  • dates : java.util.Date的功能方法類。

  • calendars : 類似#dates,面向java.util.Calendar

  • numbers : 格式化數字的功能方法類

  • strings : 字符串對象的功能類,contains,startWiths,prepending/appending等等。

  • objects: 對objects的功能類操作。

  • bools: 對布爾值求值的功能方法。

  • arrays:對數組的功能類方法。

  • lists: 對lists功能類方法

  • sets

  • maps
    ...

  • 下面用一段代碼來舉例一些常用的方法:
    dates
    /*
    * Format date with the specified pattern
    * Also works with arrays, lists or sets
    */
    ${#dates.format(date, 'dd/MMM/yyyy HH:mm')}
    ${#dates.arrayFormat(datesArray, 'dd/MMM/yyyy HH:mm')}
    ${#dates.listFormat(datesList, 'dd/MMM/yyyy HH:mm')}
    ${#dates.setFormat(datesSet, 'dd/MMM/yyyy HH:mm')}
    /*
    * Create a date (java.util.Date) object for the current date and time
    */
    ${#dates.createNow()}
    /*
    * Create a date (java.util.Date) object for the current date (time set to 00:00)
    */
    ${#dates.createToday()}

    strings
    /*
    * Check whether a String is empty (or null). Performs a trim() operation before check
    * Also works with arrays, lists or sets
    */
    ${#strings.isEmpty(name)}
    ${#strings.arrayIsEmpty(nameArr)}
    ${#strings.listIsEmpty(nameList)}
    ${#strings.setIsEmpty(nameSet)}
    /*
    * Check whether a String starts or ends with a fragment
    * Also works with arrays, lists or sets
    */
    ${#strings.startsWith(name,'Don')} // also array*, list* and set*
    ${#strings.endsWith(name,endingFragment)} // also array*, list* and set*
    /*
    * Compute length
    * Also works with arrays, lists or sets
    */
    ${#strings.length(str)}
    /*
    * Null-safe comparison and concatenation
    */
    ${#strings.equals(str)}
    ${#strings.equalsIgnoreCase(str)}
    ${#strings.concat(str)}
    ${#strings.concatReplaceNulls(str)}
    /*
    * Random
    */
    ${#strings.randomAlphanumeric(count)}

    使用thymeleaf布局
    使用thymeleaf布局非常的方便
    定義代碼片段
    <footer th:fragment="copy"> 
    &copy; 2016
    </footer>

    在頁面任何地方引入:
    <body> 
    <div th:include="footer :: copy"></div>
    <div th:replace="footer :: copy"></div>
    </body>

    th:include 和 th:replace區別,include只是加載,replace是替換
    返回的HTML如下:
    <body> 
    <div> &copy; 2016 </div>
    <footer>&copy; 2016 </footer>
    </body>

    下面是一個常用的后臺頁面布局,將整個頁面分為頭部,尾部、菜單欄、隱藏欄,點擊菜單只改變content區域的頁面
    <body class="layout-fixed">
    <div th:fragment="navbar" class="wrapper" role="navigation">
    <div th:replace="fragments/header :: header">Header</div>
    <div th:replace="fragments/left :: left">left</div>
    <div th:replace="fragments/sidebar :: sidebar">sidebar</div>
    <div layout:fragment="content" id="content" ></div>
    <div th:replace="fragments/footer :: footer">footer</div>
    </div>
    </body>

    任何頁面想使用這樣的布局值只需要替換中見的 content模塊即可
     <html xmlns:th="http://www.thymeleaf.org" layout:decorator="layout">
    <body>
    <section layout:fragment="content">
    ...

    也可以在引用模版的時候傳參
    <head th:include="layout :: htmlhead" th:with="title='Hello'"></head>

    layout 是文件地址,如果有文件夾可以這樣寫 fileName/layout:htmlhead
    htmlhead 是指定義的代碼片段 如 th:fragment="copy"
    源碼案例
    這里有一個開源項目幾乎使用了這里介紹的所有標簽和布局,大家可以參考:
    cloudfavorites
    參考
    thymeleaf官方指南
    新一代Java模板引擎Thymeleaf
    Thymeleaf基本知識
    thymeleaf總結文章
    Thymeleaf 模板的使用
    thymeleaf 學習筆記


    作者:純潔的微笑
    出處:http://www.ityouknow.com/
    版權所有,歡迎保留原文鏈接進行轉載:)
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(1,391)

    • 個人分類:生活學習
    ▲top
    • 3月 15 週三 201722:41
    • 一個腳本引發的血案


    文章出處
    我們本身是一家互聯網金融公司,公司的主流業務就是p2p,因為各種原因吧,15年底啟動建設眾籌平臺。考慮到前期開發過程中的一些弊端和架構經驗,本次架構引用了dubbo做soa服務的治理,web容器nginx+tomcat,后端語言采用java,框架選擇spring+mybaits,前端模板引擎使用的是btl,app采用原生+h5的模式。這個架構可以參考我之前寫的文章從零到百億互聯網金融架構發展史中的第三代系統架構,之前的文章主要介紹了架構的變遷,本篇文章主要介紹在第三代平臺中遇到的問題以及解決方法。
    首先介紹一下眾籌系統的部署架構(如下圖),網站和app請求都是首先到最前端的nginx,如果只是靜態內容的訪問nginx直接處理后返回;動態請求分別轉發到后端的tomcat前端服務層,前端服務層只關注頁面端業務邏輯不涉及數據庫的操作,如果只是頁面框架渲染以及不涉及數據庫的請求,在前端服務層直接處理返回;如果涉及到數據庫操作或者核心業務邏輯,前端服務層通過dubbo調用后端的接入層服務或者核心層服務。
    上線在生產測試期間,發現tomcat過一段時間就會莫名奇妙的down掉,特別是后端的tomcat down掉的頻率比較高。后端的tomcat down掉之后對前端的頁面展示沒有影響,會影響后端的交易。
    jvm參數配置
    查看tomcat業務日志,報錯如下:
    2016-04-14 12:01:55,025 - org.jboss.netty.channel.DefaultChannelPipeline -59679839 [New I/O worker #29] WARN null - [DUBBO] An exception was thrown by a user handler while handling an exception event ([id: 0x5f980c11, /xxx:55386 => /xxx:6666] EXCEPTION: com.alibaba.dubbo.remoting.ExecutionException: class com.alibaba.dubbo.remoting.transport.dispatcher.all.AllChannelHandler error when process received event .), dubbo version: 2.8.4, current host: xxx
    com.alibaba.dubbo.remoting.ExecutionException: class com.alibaba.dubbo.remoting.transport.dispatcher.all.AllChannelHandler error when process caught event .
    at com.alibaba.dubbo.remoting.transport.dispatcher.all.AllChannelHandler.caught(AllChannelHandler.java:67)
    at com.alibaba.dubbo.remoting.transport.AbstractChannelHandlerDelegate.caught(AbstractChannelHandlerDelegate.java:44)
    at com.alibaba.dubbo.remoting.transport.AbstractChannelHandlerDelegate.caught(AbstractChannelHandlerDelegate.java:44)
    at com.alibaba.dubbo.remoting.transport.AbstractPeer.caught(AbstractPeer.java:127)
    at com.alibaba.dubbo.remoting.transport.netty.NettyHandler.exceptionCaught(NettyHandler.java:112)
    at com.alibaba.dubbo.remoting.transport.netty.NettyCodecAdapter$InternalDecoder.exceptionCaught(NettyCodecAdapter.java:165)
    at org.jboss.netty.channel.Channels.fireExceptionCaught(Channels.java:525)
    at org.jboss.netty.channel.AbstractChannelSink.exceptionCaught(AbstractChannelSink.java:48)
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:296)
    at com.alibaba.dubbo.remoting.transport.netty.NettyCodecAdapter$InternalDecoder.messageReceived(NettyCodecAdapter.java:148)
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:268)
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:255)
    at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:88)
    at org.jboss.netty.channel.socket.nio.AbstractNioWorker.process(AbstractNioWorker.java:109)
    at org.jboss.netty.channel.socket.nio.AbstractNioSelector.run(AbstractNioSelector.java:312)
    at org.jboss.netty.channel.socket.nio.AbstractNioWorker.run(AbstractNioWorker.java:90)
    at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:178)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)
    Caused by: java.lang.OutOfMemoryError: unable to create new native thread
    at java.lang.Thread.start0(Native Method)
    at java.lang.Thread.start(Thread.java:714)
    at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:949)
    at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1360)
    at com.alibaba.dubbo.remoting.transport.dispatcher.all.AllChannelHandler.caught(AllChannelHandler.java:65)
    ... 19 more

    查看output日志,發現其中有這么一句。
    SEVERE: The web application [/xxx] appears to have started a thread named [DubboResponseTimeoutScanTimer] but has failed to stop it. This is very likely to create a memory leak.
    根據日志提示貌似有內存泄露,以前確實還沒有碰到過這個錯誤,一片迷茫。重新啟動后,先用命令jstat -gc xxx 1000 30查看java 進程的gc情況,發現在30秒的世界內minor gc了n次,隨懷疑年輕代內存配置少了,查看個區域內存的配置參數如下:
    -Xms10g -Xmx10g -XX:PermSize=1g -XX:MaxPermSize=2g -Xshare:off -Xmn1024m
    按照年輕代為堆內存為百分之三的原則修改為-Xmn4g,重新啟動觀察之后mimor gc的頻率確實有所下降,測試大約過了3小時候之后又反饋tomcat down掉了,繼續分析啟動參數配置的時候發現了這么一句-XX:-+DisableExplicitGC,顯示的禁止了System.gc(),但是使用了java.nio的大量框架中使用System.gc()來執行gc期通過full gc來強迫已經無用的DirectByteBuffer對象釋放掉它們關聯的native memory,如果禁用會導致OOM,隨即懷疑是否是這個參數引發的問題,在啟動參數中去掉它。
    為了防止再次出現異常的時候能更加詳細的分析堆內存的使用情況,在啟動參數中添加了-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/logs/java/,當tomcat down的時候讓輸出堆內存文件,一邊也啟動jvisualvm工具來實時的監控內存各個線程的使用情況。
    數據庫連接池
    繼續使用壓測工具來壓測,在壓測的過程中發現名為com.mchange.v2.resourcepool.ssync.ThreadPoolAsynchronousRunner$PoolThred-#xxx的線程不斷的增長,并且后臺tomcat報錯如下:
    2016-04-13 16:55:15,175 - com.alibaba.dubbo.common.threadpool.support.AbortPolicyWithReport -83649035 [New I/O worker #27] WARN - [DUBBO] Thread pool is EXHAUSTED! Thread Name: DubboServerHandler-xxx:6666, Pool Size: 200 (active: 200, core: 200, max: 200, largest: 200), Task: 692 (completed: 492), Executor status:(isShutdown:false, isTerminated:false, isTerminating:false), in dubbo://xxx:6666!, dubbo version: 2.8.4, current host: xxx
    2016-04-13 16:55:15,176 - com.alibaba.dubbo.common.threadpool.support.AbortPolicyWithReport -83649036 [New I/O worker #27] WARN - [DUBBO] Thread pool is EXHAUSTED! Thread Name: DubboServerHandler-xxx:6666, Pool Size: 200 (active: 200, core: 200, max: 200, largest: 200), Task: 692 (completed: 492), Executor status:(isShutdown:false, isTerminated:false, isTerminating:false), in dubbo://xxx:6666!, dubbo version: 2.8.4, current host: xxx
    2016-04-13 16:55:15,177 - org.jboss.netty.channel.DefaultChannelPipeline -83649037 [New I/O worker #27] WARN - [DUBBO] An exception was thrown by a user handler while handling an exception event ([id: 0x2f345d45, /192.168.57.20:36475 => /xxx:6666] EXCEPTION: com.alibaba.dubbo.remoting.ExecutionException: class com.alibaba.dubbo.remoting.transport.dispatcher.all.AllChannelHandler error when process received event .), dubbo version: 2.8.4, current host: xxx
    com.alibaba.dubbo.remoting.ExecutionException: class com.alibaba.dubbo.remoting.transport.dispatcher.all.AllChannelHandler error when process caught event .
    at com.alibaba.dubbo.remoting.transport.dispatcher.all.AllChannelHandler.caught(AllChannelHandler.java:67)
    at com.alibaba.dubbo.remoting.transport.AbstractChannelHandlerDelegate.caught(AbstractChannelHandlerDelegate.java:44)
    at com.alibaba.dubbo.remoting.transport.AbstractChannelHandlerDelegate.caught(AbstractChannelHandlerDelegate.java:44)
    at com.alibaba.dubbo.remoting.transport.AbstractPeer.caught(AbstractPeer.java:127)
    at com.alibaba.dubbo.remoting.transport.netty.NettyHandler.exceptionCaught(NettyHandler.java:112)
    at com.alibaba.dubbo.remoting.transport.netty.NettyCodecAdapter$InternalDecoder.exceptionCaught(NettyCodecAdapter.java:165)
    at org.jboss.netty.channel.Channels.fireExceptionCaught(Channels.java:525)
    at org.jboss.netty.channel.AbstractChannelSink.exceptionCaught(AbstractChannelSink.java:48)
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:296)
    at com.alibaba.dubbo.remoting.transport.netty.NettyCodecAdapter$InternalDecoder.messageReceived(NettyCodecAdapter.java:148)
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:268)
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:255)
    at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:88)
    at org.jboss.netty.channel.socket.nio.AbstractNioWorker.process(AbstractNioWorker.java:109)
    at org.jboss.netty.channel.socket.nio.AbstractNioSelector.run(AbstractNioSelector.java:312)
    at org.jboss.netty.channel.socket.nio.AbstractNioWorker.run(AbstractNioWorker.java:90)
    at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:178)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)
    Caused by: java.util.concurrent.RejectedExecutionException: Thread pool is EXHAUSTED! Thread Name: DubboServerHandler-xxx:6666, Pool Size: 200 (active: 200, core: 200, max: 200, largest: 200), Task: 692 (completed: 492), Executor status:(isShutdown:false, isTerminated:false, isTerminating:false), in dubbo://xxx:6666!
    at com.alibaba.dubbo.common.threadpool.support.AbortPolicyWithReport.rejectedExecution(AbortPolicyWithReport.java:53)
    at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:821)
    at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1372)
    at com.alibaba.dubbo.remoting.transport.dispatcher.all.AllChannelHandler.caught(AllChannelHandler.java:65)
    ... 19 more

    根據這些信息隨懷疑數據庫連接池有問題,為了更好的監控連接池的使用,因此前期使用c3p0也會出現的一些問題,所以我們決定將數據庫連接池替換成druid,已經在別的項目中使用測試過,因此非常快速的更換投產。投產后繼續用壓測工具來測試,根據druid的后臺監控頁面發現(項目地址/druid/index.html),每次前端掉用一次數據庫連接就加一次,執行完成之后數據庫連接并沒有釋放。如下圖紅色區域,我們將數據庫連接池調整成1000,不一會就占滿了。
    根據這些信息判斷出,數據庫執行sql后肯定沒有釋放數據庫連接,導致數據庫連接池用滿后,后續的線程無法執行,檢查代碼之后發現果然有問題,請看下方代碼,我們最先使用的是SqlSessionFactory,如果使用SqlSessionFactory,在執行完sql后必須要執行session.close()來關閉連接,才會被連接池重新回收。
    public class SessionFactory {
    @Resource
    private SqlSessionFactory coreSqlSessionFactory;
    protected SqlSession getSession() {
    return coreSqlSessionFactory.openSession();
    }
    }

    public class BaseDao extends SessionFactory{
    public void add(Entity entity) {
    this.getSession().update(entity.getClass().getSimpleName()+"."+Thread.currentThread().getStackTrace()[2].getMethodName(), entity);
    }
    }

    但是使用SqlSessionTemplate卻不用手動執行代碼來關閉session,因此我們把上面SessionFactory類中的代碼改成SqlSessionTemplate(如下),此問題便解決了。
    public class SessionFactory {
    @Resource
    public SqlSessionTemplate coreSqlSession;
    protected SqlSessionTemplate getSession() {
    return coreSqlSession;
    }
    }

    詭異的腳本
    做完上面的優化之后,我們感覺問題應該解決了,但過了一段時間后tomcat又詭異的掛了,繼續分析gc情況,分階段使用jmap -dump:live,format=b,file=dump.hprof xxx命令生成堆轉儲快照來對比堆內存使用情況,監控線程使用情況,均發現沒有問題。這個問題困擾了我們好幾天,每天都監控這端口,一但發現tomcat down之后馬上通知運營人員重啟。一方面我們也查閱了各種資料,到網上查找各種tomcat自動down的原因,一一在我們服務器進行了測試、修復均不起作用。
    終于在google各種tomcat down原因的時候發現了這么一篇文章Tomcat進程意外退出的問題分析,立刻想起了我們最近使用的一個腳本來,因為我們的tomcat禁止了通過bat文件來關閉,因此為了啟動方便我們寫了一個腳本文件,方便通過腳本來啟動、停止、重啟tomcat文件,這是這個腳本導致tomcat down的原因,不不,不叫原因叫元兇!腳本內容如下:
    #!/bin/sh
    # eg: tomcat.sh start xxx
    #
    proc_dir="/usr/local/xxx/tomcat-zc-web/bin"
    proc_name=$2
    if [ x$proc_name != x ]
    then
    proc_dir=${proc_dir//xxx/$proc_name}
    fi
    #echo $proc_dir
    function stop () {
    kill -9 `ps -ef |grep $proc_dir |grep -v grep|awk '{print $2}'`
    }
    function start () {
    cd $proc_dir
    ./startup.sh
    tail -300f /usr/local/logs/tomcat-business/$proc_name.log
    }
    case $1 in
    start)
    start;;
    stop)
    stop;;
    restart)
    stop
    start;;
    esac

    就是因為tail -300f /usr/local/logs/tomcat-business/$proc_name.log這一句導致的問題,在別的項目使用的時候其實是沒有這一句的,一般在使用的步驟是:
  • 1 執行tomcat.sh start xxx啟動tomcat,

  • 2 執行tail -300f /usr/local/logs/tomcat-business/xxx.log 查看啟動日志是否成功。

  • 在這次投產的時候為了省一步操作,就將執行查看日志的命令,直接加在了啟動命令的后面,當執行tomcat.sh start xxx這個命令的時候,即啟動的tomcat,也自動會打印出tomcat的日志,那時候的想法非常好。
    原因是,使用腳本命令啟動后因為使用了tail -300f xxx 命令,tomcat的進程會成為shell腳本的子進程,這樣的話,如過shell腳本停止的話,系統會自動殺掉tomcat進程導致tomcat down掉,在我們的腳本中去掉這條命令tomcat就正常了,更深層次的原因參考Tomcat進程意外退出的問題分析這篇文章,文章的內容還是分析的比較透徹,最后感覺阿里的技術真的很牛X,這篇文章也是出自于阿里的員工。

    經歷這么些波折,后續的tomcat服務終于穩定了下來




    作者:純潔的微笑
    出處:http://www.ityouknow.com/
    版權歸作者所有,轉載請注明出處
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(22)

    • 個人分類:生活學習
    ▲top
    • 3月 15 週三 201722:41
    • python3爬取1024圖片

    list
    文章出處
    這兩年python特別火,火到博客園現在也是隔三差五的出現一些python的文章。各種開源軟件、各種爬蟲算法紛紛開路,作為互聯網行業的IT狗自然看的我也是心癢癢,于是趁著這個霧霾橫行的周末瞅了兩眼,作為一名老司機覺得還是應該以練帶學,1024在程序員界這么流行的網站,當然拿來先練一練。
    python自稱是以自然語言的視角來編程,特點是開發快,語言簡潔,沒那么多技巧,大名鼎鼎的豆瓣、youtube都是使用python開發的網站,看來python在大規模使用這個方面來講應該沒有啥子問題;python也不是沒有缺點在性能方面就Java、C++等老前輩還是沒得比的,另外python和nodejs一樣只能使用CPU單核,也是性能方面影響是因素之一。但python在特定領域表現突出,特別是腳本、爬蟲、科學算法等。

    好了,還是說正事如何爬取1024網站的圖片


    分析
    列表頁面
    首先進入1024的導航網站,隨便點擊一個地址進入選擇圖片區或者在網站地址后面添加thread0806.php?fid=16&search=&page=,這就是1024網站的圖片區,這個爬蟲就是主要抓取這個區域的所有圖片,使用瀏覽器debug分析一下這個頁面發現基本都是列表頁,格式如下:
    在地址欄http://xxxxxx.biz/thread0806.php?fid=16&search=&page=后面拼1、2、3等于就是訪問圖片區第一頁、第二頁、第三頁的列表頁。根據這些列表頁就可以爬出具體的每一個圖片頁的地址,類似上圖的地址:htm_data/16/1611/2114702.html 在地址的前面拼接上主站地址就是具體的圖片頁了。所以根據以上的分析:通過循環地址欄找到不同的列表頁在根據列表頁找到具體的圖片頁

    地址欄->圖片列表->圖片頁地址


    獲取列表頁圖片地址代碼如下:
    import urllib.request,socket,re,sys,os
    baseUrl='http://xxxx.biz/'
    def getContant(Weburl):
    Webheader= {'Upgrade-Insecure-Requests':'1',
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.103 Safari/537.36',}
    req = urllib.request.Request(url = Weburl,headers=Webheader)
    respose = urllib.request.urlopen(req)
    _contant = respose.read()
    respose.close()
    return str(_contant)
    def getUrl(URL):
    pageIndex = 1
    for i in range(1,int(pageIndex)+1):
    Weburl = URL + str(i)
    contant = getContant(Weburl)
    comp = re.compile(r'<a href="htm_data.{0,30}html" target="_blank" id=""><font color=g')
    urlList1 = comp.findall(contant)
    comp = re.compile(r'a href="(.*?)"')
    urlList2 = comp.findall(str(urlList1))
    urlList = []
    for url1 in urlList2:
    url2 = baseUrl+url1
    urlList.append(url2)
    return urlList
    URL = baseUrl+'thread0806.php?fid=16&search=&page='
    UrlList = getUrl(URL)
    print(UrlList)

    在這個地址后面拼接1到N就是不同的列表頁


    圖片頁面
    利用瀏覽器debug一下頁面,圖片基本上都是外鏈地址,以http或者https開頭以jpg、png、gif結尾,寫個正則表達式匹配這些地址,然后交給程序下載就OK了。
    頁面代碼如下:
    在下載過程中遇到了幾個問題,就是有的頁面會報403禁止訪問等,應該是網站加了一些防止爬蟲的手段,網上找了下加上header參數來模擬瀏覽器訪問就解決了;
    下載單個頁面代碼如下:
    import urllib.request,socket,re,sys,os
    #定義文件保存路徑
    targetPath = "D:\\temp\\1024\\1"
    def openUrl(url):
    headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) ' 'Chrome/51.0.2704.63 Safari/537.36'
    }
    req = urllib.request.Request(url=url, headers=headers)
    res = urllib.request.urlopen(req)
    data = res.read()
    downImg(data)
    def downImg(data):
    for link,t in set(re.findall(r'([http|https]:[^\s]*?(jpg|png|gif))', str(data))):
    if link.startswith('s'):
    link='http'+link
    else:
    link='htt'+link
    print(link)
    try:
    opener=urllib.request.build_opener()
    opener.addheaders=[('User-Agent','Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1941.0 Safari/537.36')]
    urllib.request.install_opener(opener)
    urllib.request.urlretrieve(link,saveFile(link))
    except:
    print('失敗')
    def saveFile(path):
    #檢測當前路徑的有效性
    if not os.path.isdir(targetPath):
    os.mkdir(targetPath)
    #設置每個圖片的路徑
    pos = path.rindex('/')
    t = os.path.join(targetPath,path[pos+1:])
    return t
    url = "http://xxxx.biz/htm_data/16/1611/2115193.html"
    openUrl(url)

    批量爬取
    批量爬取有兩個工作要做,第一for循環目標內的所有列表頁,第二為了避免重復爬取,需要給每個頁面建立唯一的文件夾,下次爬取的時候如果存在直接跳過。最后在理一下所有的爬取步驟:

    循環地址欄->找出圖片頁列表->圖片頁分析找出圖片地址->為圖片頁建立唯一的文件夾->開始下載頁面圖片


    完整的代碼如下:
    import urllib.request,socket,re,sys,os
    baseUrl='http://xxxx.biz/'
    targetPath = "D:\\temp\\1024\\"
    def getContant(Weburl):
    Webheader= {'Upgrade-Insecure-Requests':'1',
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.103 Safari/537.36',}
    req = urllib.request.Request(url = Weburl,headers=Webheader)
    respose = urllib.request.urlopen(req)
    _contant = respose.read()
    respose.close()
    return str(_contant)
    def getUrl(URL):
    pageIndex = 1
    for i in range(1,int(pageIndex)+1):
    Weburl = URL + str(i)
    contant = getContant(Weburl)
    comp = re.compile(r'<a href="htm_data.{0,30}html" target="_blank" id=""><font color=g')
    urlList1 = comp.findall(contant)
    comp = re.compile(r'a href="(.*?)"')
    urlList2 = comp.findall(str(urlList1))
    urlList = []
    for url1 in urlList2:
    url2 = baseUrl+url1
    urlList.append(url2)
    return urlList
    def openUrl(url):
    headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) ' 'Chrome/51.0.2704.63 Safari/537.36'
    }
    filePath=targetPath+url[-12:-5]
    #檢測當前路徑的有效性
    if not os.path.isdir(filePath):
    os.mkdir(filePath)
    req = urllib.request.Request(url=url, headers=headers)
    res = urllib.request.urlopen(req)
    data = res.read()
    downImg(data,filePath)
    else:
    print("已經下載過的地址跳過:"+url)
    print("filePath "+filePath)
    def downImg(data,filePath):
    for link,t in set(re.findall(r'([http|https]:[^\s]*?(jpg|png|gif))', str(data))):
    if link.startswith('s'):
    link='http'+link
    else:
    link='htt'+link
    print(link)
    try:
    opener=urllib.request.build_opener()
    opener.addheaders=[('User-Agent','Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1941.0 Safari/537.36')]
    urllib.request.install_opener(opener)
    urllib.request.urlretrieve(link,saveFile(link,filePath))
    except:
    print('失敗')
    def saveFile(path,filePath):
    #設置每個圖片的路徑
    pos = path.rindex('/')
    t = os.path.join(filePath,path[pos+1:])
    return t
    def openPage(UrlList):
    for pageUlr in UrlList:
    try:
    print('正在下載地址:'+pageUlr)
    openUrl(pageUlr)
    except:
    print('地址:'+pageUlr+'下載失敗')
    URL = baseUrl+'thread0806.php?fid=16&search=&page='
    for num in range(0,20):#0-20頁
    print("#######################################")
    print("##########總目錄下載地址###############")
    print(URL+str(num))
    print("#######################################")
    print("#######################################")
    UrlList = getUrl(URL+str(num))
    openPage(UrlList)

    最后的爬取結果:

    源代碼地址:python-crawler
    具體地址和源代碼在一起


    其它
    關于python2和python3的爭論,網站爭論比較大python3不兼容pyhton2,很多第三方的類庫暫時還沒有支持python3等等,但是對于我們新手來說,肯定是往前看果斷python3.
    代碼比較冗余幾個地方還沒有寫好,還在慢慢學習中,目前只是搞的可以跑起來。還有幾個問題沒有解決,下載一段時間后會莫名其妙的斷掉目前還么找到原因,后期看是否可以加上多線程來爬取可能會快一點,大家有什么更好的建議也可以提出來。
    參考:
    爬取豆瓣首頁圖片
    使用Python爬取1024上的圖片


    作者:純潔的微笑
    出處:http://www.ityouknow.com/
    版權所有,歡迎保留原文鏈接進行轉載:)
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(27)

    • 個人分類:生活學習
    ▲top
    • 3月 15 週三 201722:41
    • spring boot(三):Spring Boot中Redis的使用


    文章出處
    spring boot對常用的數據庫支持外,對nosql 數據庫也進行了封裝自動化。
    redis介紹
    Redis是目前業界使用最廣泛的內存數據存儲。相比memcached,Redis支持更豐富的數據結構,例如hashes, lists, sets等,同時支持數據持久化。除此之外,Redis還提供一些類數據庫的特性,比如事務,HA,主從庫。可以說Redis兼具了緩存系統和數據庫的一些特性,因此有著豐富的應用場景。本文介紹Redis在Spring Boot中兩個典型的應用場景。
    如何使用
    1、引入 spring-boot-starter-redis
    <dependency> 
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-redis</artifactId>
    </dependency>

    2、添加配置文件
    # REDIS (RedisProperties)
    # Redis數據庫索引(默認為0)
    spring.redis.database=0
    # Redis服務器地址
    spring.redis.host=192.168.0.58
    # Redis服務器連接端口
    spring.redis.port=6379
    # Redis服務器連接密碼(默認為空)
    spring.redis.password=
    # 連接池最大連接數(使用負值表示沒有限制)
    spring.redis.pool.max-active=8
    # 連接池最大阻塞等待時間(使用負值表示沒有限制)
    spring.redis.pool.max-wait=-1
    # 連接池中的最大空閑連接
    spring.redis.pool.max-idle=8
    # 連接池中的最小空閑連接
    spring.redis.pool.min-idle=0
    # 連接超時時間(毫秒)
    spring.redis.timeout=0

    3、添加cache的配置類
    @Configuration
    @EnableCaching
    public class RedisConfig extends CachingConfigurerSupport{
    @Bean
    public KeyGenerator keyGenerator() {
    return new KeyGenerator() {
    @Override
    public Object generate(Object target, Method method, Object... params) {
    StringBuilder sb = new StringBuilder();
    sb.append(target.getClass().getName());
    sb.append(method.getName());
    for (Object obj : params) {
    sb.append(obj.toString());
    }
    return sb.toString();
    }
    };
    }
    @SuppressWarnings("rawtypes")
    @Bean
    public CacheManager cacheManager(RedisTemplate redisTemplate) {
    RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
    //設置緩存過期時間
    //rcm.setDefaultExpiration(60);//秒
    return rcm;
    }
    @Bean
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
    StringRedisTemplate template = new StringRedisTemplate(factory);
    Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    ObjectMapper om = new ObjectMapper();
    om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    jackson2JsonRedisSerializer.setObjectMapper(om);
    template.setValueSerializer(jackson2JsonRedisSerializer);
    template.afterPropertiesSet();
    return template;
    }
    }

    3、好了,接下來就可以直接使用了
    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringApplicationConfiguration(Application.class)
    public class TestRedis {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedisTemplate redisTemplate;
    @Test
    public void test() throws Exception {
    stringRedisTemplate.opsForValue().set("aaa", "111");
    Assert.assertEquals("111", stringRedisTemplate.opsForValue().get("aaa"));
    }
    @Test
    public void testObj() throws Exception {
    User user=new User("aa@126.com", "aa", "aa123456", "aa","123");
    ValueOperations<String, User> operations=redisTemplate.opsForValue();
    operations.set("com.neox", user);
    operations.set("com.neo.f", user,1,TimeUnit.SECONDS);
    Thread.sleep(1000);
    //redisTemplate.delete("com.neo.f");
    boolean exists=redisTemplate.hasKey("com.neo.f");
    if(exists){
    System.out.println("exists is true");
    }else{
    System.out.println("exists is false");
    }
    // Assert.assertEquals("aa", operations.get("com.neo.f").getUserName());
    }
    }

    以上都是手動使用的方式,如何在查找數據庫的時候自動使用緩存呢,看下面;
    4、自動根據方法生成緩存
    @RequestMapping("/getUser")
    @Cacheable(value="user-key")
    public User getUser() {
    User user=userRepository.findByUserName("aa");
    System.out.println("若下面沒出現“無緩存的時候調用”字樣且能打印出數據表示測試成功");
    return user;
    }

    其中value的值就是緩存到redis中的key
    共享Session-spring-session-data-redis
    分布式系統中,sessiong共享有很多的解決方案,其中托管到緩存中應該是最常用的方案之一,
    Spring Session官方說明
    Spring Session provides an API and implementations for managing a user’s session information.
    如何使用
    1、引入依賴
    <dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
    </dependency>

    2、Session配置:
    @Configuration
    @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 86400*30)
    public class SessionConfig {
    }

    maxInactiveIntervalInSeconds: 設置Session失效時間,使用Redis Session之后,原Boot的server.session.timeout屬性不再生效


    好了,這樣就配置好了,我們來測試一下
    3、測試
    添加測試方法獲取sessionid
    @RequestMapping("/uid")
    String uid(HttpSession session) {
    UUID uid = (UUID) session.getAttribute("uid");
    if (uid == null) {
    uid = UUID.randomUUID();
    }
    session.setAttribute("uid", uid);
    return session.getId();
    }

    登錄redis 輸入 keys '*sessions*'
    t<spring:session:sessions:db031986-8ecc-48d6-b471-b137a3ed6bc4
    t(spring:session:expirations:1472976480000

    其中 1472976480000為失效時間,意思是這個時間后session失效,db031986-8ecc-48d6-b471-b137a3ed6bc4 為sessionId,登錄http://localhost:8080/uid 發現會一致,就說明session 已經在redis里面進行有效的管理了。
    如何在兩臺或者多臺中共享session
    其實就是按照上面的步驟在另一個項目中再次配置一次,啟動后自動就進行了session共享。
    示例代碼地址
    參考
    Redis的兩個典型應用場景
    pringBoot應用之分布式會話


    作者:純潔的微笑
    出處:www.ityouknow.com
    版權所有,歡迎保留原文鏈接進行轉載:)
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(210)

    • 個人分類:生活學習
    ▲top
    • 3月 15 週三 201722:41
    • 文章匯總索引


    文章出處
    近期文章
  • 百億互金平臺救火故事

  • jvm系列(八):jvm知識點總覽-高級Java工程師面試必備

  • jvm系列(七):jvm調優-工具篇

  • 實戰
  • 一次生產事故的優化經歷

  • 一次dns緩存引發的慘案

  • 一個腳本引發的血案

  • 百億互金平臺救火故事

  • 從零到百億互聯網金融架構發展史

  • 生活
  • 六年程序生涯

  • 程序員該用哪種姿勢來理財

  • 2016顛倒夢想,2017靜心前行

  • 發現另外一個世界-網盤關閉背后

  • spring boot
  • springboot(一):入門篇

  • springboot(二):web綜合開發

  • springboot(三):Spring boot中Redis的使用

  • springboot(四):thymeleaf使用詳解

  • springboot(五):spring data jpa的使用

  • springboot(六):如何優雅的使用mybatis

  • springboot(七):springboot+mybatis多數據源最簡解決方案

  • springboot(八):RabbitMQ詳解

  • springboot(九):定時任務

  • springboot實戰:我們的第一款開源軟件

  • JVM
  • jvm系列(一):java類的加載機制

  • jvm系列(二):JVM內存結構

  • jvm系列(三):GC算法 垃圾收集器

  • jvm系列(四):jvm調優-命令篇

  • jvm系列(五):tomcat性能調優和性能監控(visualvm)

  • jvm系列(六):jvm調優-從eclipse開始

  • jvm系列(七):jvm調優-工具篇

  • jvm系列(八):jvm知識點總覽-高級Java工程師面試必備

  • 爬蟲
  • python3爬取1024圖片

  • 網貸之家的爬蟲之旅

  • 抓取某一個網站整站的記錄

  • 運維
  • linux定時備份mysql并同步到其它服務器

  • Elasticsearch、Logstash、Kibana搭建統一日志分析平臺

  • 大數據實踐-數據同步篇tungsten-relicator(mysql->mongo)

  • 網站文件系統發展&&分布式文件系統fastDFS

  • spring
  • spring aop

  • spring ioc

  • spring 多數據源一致性事務方案

  • (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(4)

    • 個人分類:生活學習
    ▲top
    • 3月 15 週三 201722:41
    • jvm系列(七):jvm調優-工具篇


    文章出處
    16年的時候花了一些時間整理了一些關于jvm的介紹文章,到現在回顧起來還是一些還沒有補充全面,其中就包括如何利用工具來監控調優前后的性能變化。工具做為圖形化界面來展示更能直觀的發現問題,另一方面一些耗費性能的分析(dump文件分析)一般也不會在生產直接分析,往往dump下來的文件達1G左右,人工分析效率較低,因此利用工具來分析jvm相關問題,長長可以到達事半功倍的效果來。
    jvm監控分析工具一般分為兩類,一種是jdk自帶的工具,一種是第三方的分析工具。jdk自帶工具一般在jdk bin目錄下面,以exe的形式直接點擊就可以使用,其中包含分析工具已經很強大,幾乎涉及了方方面面,但是我們最常使用的只有兩款:jconsole.exe和jvisualvm.exe;第三方的分析工具有很多,各自的側重點不同,比較有代表性的:MAT(Memory Analyzer Tool)、GChisto等。
    對于大型 JAVA 應用程序來說,再精細的測試也難以堵住所有的漏洞,即便我們在測試階段進行了大量卓有成效的工作,很多問題還是會在生產環境下暴露出來,并且很難在測試環境中進行重現。JVM 能夠記錄下問題發生時系統的部分運行狀態,并將其存儲在堆轉儲 (Heap Dump) 文件中,從而為我們分析和診斷問題提供了重要的依據。其中VisualVM和MAT是dump文件的分析利器。
    jdk自帶的工具
    jconsole
    Jconsole(Java Monitoring and Management Console)是從java5開始,在JDK中自帶的java監控和管理控制臺,用于對JVM中內存,線程和類等的監控,是一個基于JMX(java management extensions)的GUI性能監測工具。jconsole使用jvm的擴展機制獲取并展示虛擬機中運行的應用程序的性能和資源消耗等信息。
    直接在jdk/bin目錄下點擊jconsole.exe即可啟動,界面如下:
    在彈出的框中可以選擇本機的監控本機的java應用,也可以選擇遠程的java服務來監控,如果監控遠程服務需要在tomcat啟動腳本中添加如下代碼:
     -Dcom.sun.management.jmxremote.port=6969 
    -Dcom.sun.management.jmxremote.ssl=false
    -Dcom.sun.management.jmxremote.authenticate=false

    連接進去之后,就可以看到jconsole概覽圖和主要的功能:概述、內存、線程、類、VM、MBeans
  • 概述,以圖表的方式顯示出堆內存使用量,活動線程數,已加載的類,CUP占用率的折線圖,可以非常清晰的觀察在程序執行過程中的變動情況。

  • 內存,主要展示了內存的使用情況,同時可以查看堆和非堆內存的變化值對比,也可以點擊執行GC來處罰GC的執行

  • 線程,主界面展示線程數的活動數和峰值,同時點擊左下方線程可以查看線程的詳細信息,比如線程的狀態是什么,堆棧內容等,同時也可以點擊“檢測死鎖”來檢查線程之間是否有死鎖的情況。

  • 類,主要展示已加載類的相關信息。

  • VM 概要,展示JVM所有信息總覽,包括基本信息、線程相關、堆相關、操作系統、VM參數等。

  • Mbean,查看Mbean的屬性,方法等。

  • VisualVM
    簡介
    VisualVM 是一個工具,它提供了一個可視界面,用于查看 Java 虛擬機 (Java Virtual Machine, JVM) 上運行的基于 Java 技術的應用程序(Java 應用程序)的詳細信息。VisualVM 對 Java Development Kit (JDK) 工具所檢索的 JVM 軟件相關數據進行組織,并通過一種使您可以快速查看有關多個 Java 應用程序的數據的方式提供該信息。您可以查看本地應用程序以及遠程主機上運行的應用程序的相關數據。此外,還可以捕獲有關 JVM 軟件實例的數據,并將該數據保存到本地系統,以供后期查看或與其他用戶共享。
    VisualVM 是javajdk自帶的最牛逼的調優工具了吧,也是我平時使用最多調優工具,幾乎涉及了jvm調優的方方面面。同樣是在jdk/bin目錄下面雙擊jvisualvm.exe既可使用,啟動起來后和jconsole 一樣同樣可以選擇本地和遠程,如果需要監控遠程同樣需要配置相關參數,主界面如下;
    VisualVM可以根據需要安裝不同的插件,每個插件的關注點都不同,有的主要監控GC,有的主要監控內存,有的監控線程等。
    如何安裝:

    1、從主菜單中選擇“工具”>“插件”。
    2、在“可用插件”標簽中,選中該插件的“安裝”復選框。單擊“安裝”。
    3、逐步完成插件安裝程序。


    我這里以 Eclipse(pid 22296)為例,雙擊后直接展開,主界面展示了系統和jvm兩大塊內容,點擊右下方jvm參數和系統屬性可以參考詳細的參數信息.
    因為VisualVM的插件太多,我這里主要介紹三個我主要使用幾個:監控、線程、Visual GC
    監控的主頁其實也就是,cpu、內存、類、線程的圖表
    線程和jconsole功能沒有太大的區別
    Visual GC 是常常使用的一個功能,可以明顯的看到年輕代、老年代的內存變化,以及gc頻率、gc的時間等。
    以上的功能其實jconsole幾乎也有,VisualVM更全面更直觀一些,另外VisualVM非常多的其它功能,可以分析dump的內存快照,dump出來的線程快照并且進行分析等,還有其它很多的插件大家可以去探索
    第三方調優工具
    MAT
    MAT是什么?
    MAT(Memory Analyzer Tool),一個基于Eclipse的內存分析工具,是一個快速、功能豐富的Java heap分析工具,它可以幫助我們查找內存泄漏和減少內存消耗。使用內存分析工具從眾多的對象中進行分析,快速的計算出在內存中對象的占用大小,看看是誰阻止了垃圾收集器的回收工作,并可以通過報表直觀的查看到可能造成這種結果的對象。
    通常內存泄露分析被認為是一件很有難度的工作,一般由團隊中的資深人士進行。不過要介紹的 MAT(Eclipse Memory Analyzer)被認為是一個“傻瓜式“的堆轉儲文件分析工具,你只需要輕輕點擊一下鼠標就可以生成一個專業的分析報告。和其他內存泄露分析工具相比,MAT 的使用非常容易,基本可以實現一鍵到位,即使是新手也能夠很快上手使用。
    MAT以eclipse 插件的形式來安裝,具體的安裝過程就不在描述了,可以利用visualvm或者是 jmap命令生產堆文件,導入eclipse mat中生成分析報告:
    生產這會報表的同時也會在dump文件的同級目錄下生成三份(dump_Top_Consumers.zip、dump_Leak_Suspects.zip、dump_Top_Components.zip)分析結果的html文件,方便發送給相關同事來查看。
    需要關注的是下面的Actions、Reports、Step by Step區域:
  • Histogram:列出內存中的對象,對象的個數以及大小,支持正則表達式查找,也可以計算出該類所有對象的retained size

  • Dominator Tree:列出最大的對象以及其依賴存活的Object (大小是以Retained Heap為標準排序的)

  • Top Consumers : 通過圖形列出最大的object

  • duplicate classes :檢測由多個類裝載器加載的類


  • Leak Suspects :內存泄漏分析


  • Top Components: 列出大于總堆數的百分之1的報表。

  • Component Report:分析對象屬于同一個包或者被同一個類加載器加載

  • 以上只是一個初級的介紹,mat還有更強大的使用,比如對比堆內存,在生產環境中往往為了定位問題,每隔幾分鐘dump出一下內存快照,隨后在對比不同時間的堆內存的變化來發現問題。
    GChisto
    GChisto是一款專業分析gc日志的工具,可以通過gc日志來分析:Minor GC、full gc的時間、頻率等等,通過列表、報表、圖表等不同的形式來反應gc的情況。雖然界面略顯粗糙,但是功能還是不錯的。
    配置好本地的jdk環境之后,雙擊GChisto.jar,在彈出的輸入框中點擊 add 選擇gc.log日志
  • GC Pause Stats:可以查看GC 的次數、GC的時間、GC的開銷、最大GC時間和最小GC時間等,以及相應的柱狀圖

  • GC Pause Distribution:查看GC停頓的詳細分布,x軸表示垃圾收集停頓時間,y軸表示是停頓次數。


  • GC Timeline:顯示整個時間線上的垃圾收集


  • 不過這款工具已經不再維護,不能識別最新jdk的日志文件。
    gcviewer
    GCViewer也是一款分析小工具,用于可視化查看由Sun / Oracle, IBM, HP 和 BEA Java 虛擬機產生的垃圾收集器的日志,gcviewer個人感覺顯示 的界面比較亂沒有GChisto更專業一些。
    以上的兩款gc分析日志,一個不太維護了,一個不太專業,求推薦更好的gc分析工具
    前期jvm系類文章回顧:
  • jvm系列(一):java類的加載機制

  • jvm系列(二):JVM內存結構

  • jvm系列(三):GC算法 垃圾收集器

  • jvm系列(四):jvm調優-命令篇

  • jvm系列(五):tomcat性能調優和性能監控(visualvm)

  • jvm系列(六):jvm調優-從eclipse開始



  • 作者:純潔的微笑
    出處:http://www.ityouknow.com/
    版權歸作者所有,轉載請注明出處
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(63)

    • 個人分類:生活學習
    ▲top
    «123...230»

    pop-under

    參觀人氣

    • 本日人氣:
    • 累積人氣:

    線上人數

    Marquee

    最新文章

    • 文章列表
    • jvm系列(四):jvm調優-命令大全(jps jstat jmap jhat jstack jinfo)
    • spring boot(一):入門篇
    • jvm系列(一):java類的加載機制
    • jvm系列(三):java GC算法 垃圾收集器
    • spring boot 實戰:我們的第一款開源軟件
    • jvm系列(六):jvm調優-從eclipse開始
    • 混合應用技術選型
    • jvm系列(二):JVM內存結構
    • spring boot(五):spring data jpa的使用

    熱門文章

    • (1,763)jQuery之前端國際化jQuery.i18n.properties
    • (630)技術筆記:Indy控件發送郵件
    • (514)linux下安裝sqlite3
    • (501)學習筆記: Delphi之線程類TThread
    • (242)VC單選按鈕控件(Radio Button)用法(轉)
    • (104)單條件和多條件查詢
    • (51)淺談config文件的使用
    • (26)Tomcat shutdown執行后無法退出進程問題排查及解決
    • (22)基于 Asp.Net的 Comet 技術解析
    • (15)Java中的抽象類

    文章分類

    • 生活學習 (2,296)
    • 未分類文章 (1)

    最新留言

    • [20/04/24] 我是女生想約炮 有男生願意給我溫暖的嗎?我賴是woyou58 於文章「(1)從底層設計,探討插件式GIS框架的...」留言:
      我叫黎兒女生最近內心掙扎著要不要約炮我的line:woy...

    文章搜尋

    文章精選

    誰來我家

    Live Traffic Feed