目录


连接池介绍

自定义连接池

JDBC Tomcat Pool

DBCP(DataBase Connection Pool)

使用配置文件来设置DBCP

C3P0

Druid


连接池介绍

  在说连接池之前,我们先想一个问题:程序要进行数据库操作,与数据库建立的是什么连接?开销怎么样?数据库是否可以同时支持上百万个连接?

  首先第一个问题:程序与数据库建立的是socket连接,走的是传输层,使用TCP。

  第二个问题:总开销 约等于 程序运行耗时 + 网络io + 数据库运行耗时。

  第三个问题:应该是不能同时支持上百万个连接,几千个应该就是上限了。

  看了上面三个问题,再提出一个问题:上面的问题中,我们可以优化哪一个环节?

  运维可以优化网络传输的问题;DBA可以优化数据库的运行性能。

  对于开发人员来说,我们可以优化第一个问题;首先,创建socket连接真的很耗时,主要的原因是因为建立TCP连接时有个3次握手,建立连接之后传输数据开销其实并不大。所以我们可以在这个角度上进行优化:尽量让程序与数据库建立几个连接,不要让程序频繁与数据库建立连接。

  为了业务的正常执行,线程需要与数据库进行交互,只建立几个数据库连接,好像不现实。

  我们可以换个方式来优化:创建固定数量的数据库的连接,这些数据库连接在Java中就是一个个对象而已,我们可以将这些对象存到容器中(比如List中),这个容器就叫做连接池。

  当有一个线程需要与数据库交互的时候,如果容器中还有数据库连接对象,那就从容器中取出一个连接对象,使用完之后,并不关闭数据库连接,而是将数据库连接对象放回容器,方便其他线程使用;如果线程需要与数据库交互时,容器中没有数据库连接对象了,那么这个线程他就阻塞一下,等待别的线程使用完连接之后归还,然后再使用别的线程归还的数据库连接。

  

自定义连接池

  自定义连接池的有个规范,需要实现DataSource接口,并且重写多个方法,但是主要重写一个无参的getConnection方法:

  1. package cn.ganlixin.utils;
  2.  
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.io.PrintWriter;
  6. import java.sql.Connection;
  7. import java.sql.DriverManager;
  8. import java.sql.SQLException;
  9. import java.sql.SQLFeatureNotSupportedException;
  10. import java.util.Collections;
  11. import java.util.LinkedList;
  12. import java.util.List;
  13. import java.util.Properties;
  14. import java.util.logging.Logger;
  15.  
  16. import javax.sql.DataSource;
  17.  
  18. /**
  19. * 自定义的超简单的连接池,主要重写了DataSource接口中的getConnection方法,然后创建了归还连接的方法
  20. */
  21. public class MyConnectionPool implements DataSource {
  22.  
  23. // 创建一个同步的容器来保存数据库连接
  24. private static List<Connection> connectionList =
  25. Collections.synchronizedList(new LinkedList<Connection>());
  26.  
  27. // 设置建立数据库连接的最大数
  28. private static final int MAX_CONNECTIONS = 50;
  29.  
  30. // 编写静态初始化块,读取数据库配置文件,建立数据库连接,放入容器
  31. static {
  32. InputStream _is = MyConnectionPool.class.getClassLoader().getResourceAsStream("database.properties");
  33. try {
  34. Properties props = new Properties();
  35. props.load(_is);
  36. String driver = props.getProperty("jdbc.driver");
  37. String url = props.getProperty("jdbc.url");
  38. String username = props.getProperty("jdbc.username");
  39. String password = props.getProperty("jdbc.password");
  40.  
  41. Class.forName(driver);
  42.  
  43. // 创建多个连接,放入容器中
  44. for (int i = 0; i < MAX_CONNECTIONS; i++) {
  45. Connection conn = DriverManager.getConnection(url, username, password);
  46. connectionList.add(conn);
  47. System.out.println("创建第 " + (i+1) + " 个连接");
  48. }
  49.  
  50. } catch (IOException e) {
  51. e.printStackTrace();
  52. } catch (ClassNotFoundException e) {
  53. e.printStackTrace();
  54. } catch (SQLException e) {
  55. e.printStackTrace();
  56. }
  57. }
  58.  
  59. // 从容器中取出一个数据库连接对象
  60. @Override
  61. public Connection getConnection() throws SQLException {
  62.  
  63. if (connectionList.size() > 0) {
  64. // 如果容器中还有数据库连接对象,就将取出第一个对象,并将该对象从容器中删除
  65. Connection conn = connectionList.remove(0);
  66. System.out.println("使用了一个数据库连接, 容器中还剩下 " + connectionList.size() + " 个数据库连接");
  67. return conn;
  68. }
  69.  
  70. return null;
  71. }
  72.  
  73. /**
  74. * 归还数据库连接给容器,便于其他线程使用
  75. * @param conn 要归还的数据库连接对象
  76. */
  77. public void releaseConnection(Connection conn) {
  78. connectionList.add(conn);
  79. }
  80.  
  81. @Override
  82. public PrintWriter getLogWriter() throws SQLException { return null; }
  83.  
  84. @Override
  85. public void setLogWriter(PrintWriter out) throws SQLException { }
  86.  
  87. @Override
  88. public void setLoginTimeout(int seconds) throws SQLException { }
  89.  
  90. @Override
  91. public int getLoginTimeout() throws SQLException { return 0; }
  92.  
  93. @Override
  94. public Logger getParentLogger() throws SQLFeatureNotSupportedException { return null; }
  95.  
  96. @Override
  97. public <T> T unwrap(Class<T> iface) throws SQLException { return null; }
  98.  
  99. @Override
  100. public boolean isWrapperFor(Class<?> iface) throws SQLException { return false; }
  101.  
  102. @Override
  103. public Connection getConnection(String username, String password) throws SQLException { return null; }
  104.  
  105. }

  

  测试

  1. package cn.ganlixin.test;
  2.  
  3. import java.sql.Connection;
  4. import java.sql.SQLException;
  5.  
  6. public class TestPool {
  7. public static void main(String[] args) throws SQLException {
  8. MyConnectionPool connectionPool = new MyConnectionPool(); // 获取连接池
  9.  
  10. for (int i = 0; i < 20; i++) {
  11. // 获取连接
  12. Connection connection = connectionPool.getConnection();
  13.  
  14. if (i % 3 == 0) { // 归还连接
  15. connectionPool.releaseConnection(connection);
  16. }
  17.  
  18. System.out.println(connection);
  19. }
  20. }
  21. }

  

JDBC Tomcat Pool

  tomcat服务器可以提供数据库连接池。我们可以将数据库连接池的配置保存在一个文件名为context.xml的文件中。

  context.xml可以放在项目下的webRoot/META-INF目录下,只对于本项目有效。

  context.xml可以放在tomcat服务器安装路径的conf目录下,针对所有项目都有效。

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <Context>
  3. <WatchedResource>WEB-INF/web.xml</WatchedResource>
  4. <Resource
  5. driverClassName="com.mysql.jdbc.Driver"
  6. url="jdbc:mysql://localhost:3306/test"
  7. user="root"
  8. password="123456"
  9. name="tomcat_supported_pool"
  10. auth="Container"
  11. maxActive="50"
  12. maxIdle="20"
  13. maxWait="10000"
  14. type="javax.sql.DataSource"
  15. ></Resource>
  16. </Context>

  测试:

  1. package lixin.gan.test;
  2.  
  3. import java.io.IOException;
  4. import java.sql.Connection;
  5. import java.sql.SQLException;
  6.  
  7. import javax.naming.Context;
  8. import javax.naming.InitialContext;
  9. import javax.naming.NamingException;
  10. import javax.servlet.ServletException;
  11. import javax.servlet.ServletRequest;
  12. import javax.servlet.ServletResponse;
  13. import javax.servlet.annotation.WebServlet;
  14. import javax.servlet.http.HttpServlet;
  15. import javax.sql.DataSource;
  16.  
  17. /**
  18. * Servlet implementation class TestPool
  19. */
  20. @WebServlet("/TestPool")
  21. public class TestPool extends HttpServlet {
  22. @Override
  23. public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
  24. request.setCharacterEncoding("utf-8");
  25. response.setContentType("text/html; charset=utf-8");
  26.  
  27. try {
  28. Context ctx = new InitialContext();
  29. DataSource ds = (DataSource) ctx.lookup("java:comp/env/tomcat_supported_pool");
  30.  
  31. Connection conn = ds.getConnection();
  32.  
  33. /*
  34.  
  35. 进行数据库操作即可
  36.  
  37. */
  38.  
  39. } catch (NamingException e) {
  40. e.printStackTrace();
  41. } catch (SQLException e) {
  42. e.printStackTrace();
  43. }
  44.  
  45. }
  46. }

    

DBCP(DataBase Connection Pool)

  需要下载commons-dbcp.jar、commons-pool.jar、commons-logging.jar。另外仍旧需要导入mysql的驱动包。

  下载网址(下载xxx-bin.zip即可):

    http://commons.apache.org/proper/commons-dbcp/download_dbcp.cgi

    http://commons.apache.org/proper/commons-pool/download_pool.cgi

    http://commons.apache.org/proper/commons-logging/download_logging.cgi

    下载之后解压,将jar包添加到build path中。

  使用DBCP的示例:

  1. package cn.ganlixin.test;
  2.  
  3. import java.sql.Connection;
  4. import java.sql.SQLException;
  5. import java.sql.Statement;
  6.  
  7. import org.apache.commons.dbcp2.BasicDataSource;
  8.  
  9. public class TestDBCP {
  10. public static void main(String[] args) throws SQLException {
  11.  
  12. // 获取连接池
  13. BasicDataSource dataSource = new BasicDataSource();
  14.  
  15. // 设置连接池相关信息
  16. dataSource.setDriverClassName("com.mysql.jdbc.Driver");
  17. dataSource.setUrl("jdbc:mysql://localhost:3306/test");
  18. dataSource.setUsername("root");
  19. dataSource.setPassword("root");
  20. dataSource.setInitialSize(5);
  21. dataSource.setMinIdle(2);
  22.  
  23. // 获取数据库连接
  24. Connection conn = dataSource.getConnection();
  25.  
  26. // 执行数据库操作
  27. Statement stmt = conn.createStatement();
  28. stmt.executeUpdate("update stu set age = 30 where id < 4");
  29.  
  30. // 这个close()方法被重写了,并不是关闭数据库连接,而是将连接归还连接池
  31. conn.close();
  32.  
  33. }
  34. }

  

使用配置文件来设置DBCP

  前面使用DBCP时,是在程序中手动指定连接信息,同样的,我们可以使用配置文件保存DBCP的连接信息。

  操作:在src下创建一个dbcp.properties文件,内容如下:

  1. driverClassName=com.mysql.jdbc.Driver
  2. url=jdbc:mysql://localhost:3306/test
  3. username=root
  4. password=root
  5.  
  6. initialSize=20
  7. maxIdle=10
  8. minIdle=5
  9. maxWait=10000

  

  使用DBCP

  1. package cn.ganlixin.test;
  2.  
  3. import java.io.InputStream;
  4. import java.sql.Connection;
  5. import java.sql.Statement;
  6. import java.util.Properties;
  7.  
  8. import org.apache.commons.dbcp2.BasicDataSource;
  9. import org.apache.commons.dbcp2.BasicDataSourceFactory;
  10.  
  11. public class TestPool {
  12. public static void main(String[] args) throws Exception {
  13.  
  14. BasicDataSourceFactory dataSourceFacoty = new BasicDataSourceFactory();
  15.  
  16. InputStream _is = TestPool.class.getClassLoader().getResourceAsStream("dbcp.properties");
  17. Properties props = new Properties();
  18. props.load(_is);
  19.  
  20. // 获取连接池
  21. BasicDataSource dataSource = dataSourceFacoty.createDataSource(props);
  22. Connection conn = dataSource.getConnection();
  23. Statement stmt = conn.createStatement();
  24. stmt.executeUpdate("update stu set age = 30 where id < 4");
  25.  
  26. conn.close();
  27.  
  28. }
  29. }

  

DBCP返回的数据库连接是包装类对象

  当我们从DBCP连接池获取的连接其实是一个经过包装之后的数据库连接对象,而不是原生的jdbc数据库连接对象:

  1. package cn.ganlixin.test;
  2.  
  3. import java.io.InputStream;
  4. import java.sql.Connection;
  5. import java.util.Properties;
  6.  
  7. import org.apache.commons.dbcp2.BasicDataSource;
  8. import org.apache.commons.dbcp2.BasicDataSourceFactory;
  9. import org.apache.commons.dbcp2.DelegatingConnection;
  10.  
  11. public class TestDBCP1 {
  12. public static void main(String[] args) throws Exception {
  13.  
  14. BasicDataSourceFactory dataSourceFacoty = new BasicDataSourceFactory();
  15.  
  16. InputStream _is = TestPool.class.getClassLoader().getResourceAsStream("dbcp.properties");
  17.  
  18. Properties props = new Properties();
  19. props.load(_is);
  20.  
  21. BasicDataSource dataSource = dataSourceFacoty.createDataSource(props);
  22.  
  23. // 获取数据库连接
  24. Connection conn = dataSource.getConnection();
  25.  
  26. System.out.println(conn.getClass().getName());
  27. // org.apache.commons.dbcp2.PoolingDataSource$PoolGuardConnectionWrapper
  28. // 通过DBCP连接池获得的是一个包装过后的连接池对象
  29.  
  30. // 可以通过下面的步骤获取原生的Connection对象
  31. DelegatingConnection dc = (DelegatingConnection) conn;
  32. Connection connection = dc.getInnermostDelegateInternal();
  33. System.out.println(connection.getClass().getName());
  34. // com.mysql.jdbc.JDBC4Connection
  35.  
  36. }
  37. }

  

C3P0

  C3P0也是一个数据库连接池的开源项目,他和DBCP功能类似,但是有一些区别:

  1、DBCP不会自动回收空闲连接的功能,而C3P0有这个功能。

  2、DBCP需要手动指定配置文件的路径以及文件明,而C3P0不需要(C3P0的配置文件指定路径和名称)。

  

  需要下载c3p0.jar,mchange-commons-java.jar,以及mysql的驱动包。

  http://central.maven.org/maven2/com/mchange/c3p0/0.9.5.4/c3p0-0.9.5.4.jar

  http://central.maven.org/maven2/com/mchange/mchange-commons-java/0.2.15/mchange-commons-java-0.2.15.jar

创建C3P0的配置文件

  C3P0的配置文件名为c3p0-config.xml,放在src目录下即可,配置文件的内容如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <c3p0-config>
  3. <default-config>
  4. <property name="driverClass">com.mysql.jdbc.Driver</property>
  5. <property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
  6. <property name="user">root</property>
  7. <property name="password">root</property>
  8. <property name="initialPoolSize">30</property>
  9. <property name="maxIdleTime">60</property>
  10. <property name="maxPoolSize">60</property>
  11. <property name="minPoolSize">15</property>
  12. </default-config>
  13.  
  14. <!-- 可以指定两个数据库配置,一个线上环境,一个开发环境 -->
  15. <named-config name="dev">
  16. <property name=""></property>
  17. <property name=""></property>
  18. <property name=""></property>
  19. <property name=""></property>
  20. <property name=""></property>
  21. <property name=""></property>
  22. <property name=""></property>
  23. <property name=""></property>
  24. <property name=""></property>
  25. </named-config>
  26. </c3p0-config>

  

测试C3P0

  1. package cn.ganlixin.test;
  2.  
  3. import java.sql.Connection;
  4. import java.sql.SQLException;
  5. import java.sql.Statement;
  6.  
  7. import com.mchange.v2.c3p0.ComboPooledDataSource;
  8.  
  9. public class TestC3P0 {
  10. public static void main(String[] args) throws SQLException {
  11.  
  12. // 获取连接池
  13. // 加载默认的数据库连接配置
  14. // ComboPooledDataSource dataSource = new ComboPooledDataSource();
  15. // 使用c3p0配置文件中named-config里面name为dev的数据库配置
  16. ComboPooledDataSource dataSource = new ComboPooledDataSource("dev");
  17.  
  18. // 获取数据库连接
  19. Connection connection = dataSource.getConnection();
  20.  
  21. // 获取到数据库连接之后就可以进行各种操作了
  22. // code
  23.  
  24. // c3p0返回的数据库连接同样是包装类
  25. System.out.println(connection);
  26. // com.mchange.v2.c3p0.impl.NewProxyConnection@769c9116
  27. // [wrapping: com.mysql.jdbc.JDBC4Connection@6aceb1a5]
  28.  
  29. // 将数据库连接归还连接池
  30. connection.close();
  31. }
  32. }

  

  

Druid

  Druid是alibaba开源的一个连接池项目;

  使用Druid,需要下载druid.jar以及mysql的驱动包;

  druid.jar的下载地址:http://central.maven.org/maven2/com/alibaba/druid/1.1.15/druid-1.1.15.jar

  github地址:https://github.com/alibaba/druid

 使用方法设置连接池信息

  1. package cn.ganlixin.test;
  2.  
  3. import java.sql.SQLException;
  4.  
  5. import com.alibaba.druid.pool.DruidDataSource;
  6. import com.alibaba.druid.pool.DruidPooledConnection;
  7.  
  8. public class TestDruid {
  9. public static void main(String[] args) throws SQLException {
  10. // 获取连接池对象
  11. DruidDataSource dataSource = new DruidDataSource();
  12.  
  13. // 设置连接信息
  14. dataSource.setDriverClassName("com.mysql.jdbc.Driver");
  15. dataSource.setUrl("jdbc:mysql://localhost:3306/test");
  16. dataSource.setUsername("root");
  17. dataSource.setPassword("root");
  18.  
  19. // 设置连接池的配置
  20. dataSource.setInitialSize(20);
  21. dataSource.setMaxActive(30);
  22. dataSource.setMaxWait(1000);
  23. dataSource.setMinIdle(10);
  24.  
  25. // 获取连接(得到的不是原生的jdbc for mysql的连接对象)
  26. DruidPooledConnection connection = dataSource.getConnection();
  27.  
  28. // 释放连接到连接池中
  29. connection.close();
  30. }
  31. }

  

  使用properties配置文件的方式配置Druid

  配置Druid可以参考官方的示例:https://github.com/alibaba/druid/wiki/DruidDataSource%E9%85%8D%E7%BD%AE

  在src下创建druid-config.properties(文件名随意),内容如下:

  1. driverClassName=com.mysql.jdbc.Driver
  2. url=jdbc:mysql://localhost:3306/test
  3. username=root
  4. password=root
  5.  
  6. maxActive=10
  7. initialSize=5
  8. maxWait=10000
  9. minIdle=5

  配置项和DBCP几乎一样。

  进行测试:

  1. package cn.ganlixin.test;
  2.  
  3. import java.io.InputStream;
  4. import java.sql.Connection;
  5. import java.util.Properties;
  6.  
  7. import javax.sql.DataSource;
  8.  
  9. import com.alibaba.druid.pool.DruidDataSourceFactory;
  10.  
  11. public class TestDruid2 {
  12. public static void main(String[] args) throws Exception {
  13.  
  14. InputStream _is = TestDruid2.class.getClassLoader().getResourceAsStream("druid-config.properties");
  15.  
  16. Properties props = new Properties();
  17. props.load(_is);
  18.  
  19. /**
  20. 读取配置文件,手动调用setter进行设置连接池
  21. DruidDataSource dataSource = new DruidDataSource();
  22. dataSource.setDriverClassName(props.getProperty("driverClassName"));
  23. .........
  24. */
  25.  
  26. // 利用工厂加载配置文件来配置连接池
  27. DruidDataSourceFactory factory = new DruidDataSourceFactory();
  28. DataSource dataSource = factory.createDataSource(props);
  29.  
  30. // 获取数据库连接
  31. Connection connection = dataSource.getConnection();
  32. System.out.println(connection.getClass().getName());
  33.  
  34. connection.close();
  35. }
  36. }

  

Java 学习使用常见的开源连接池的更多相关文章

  1. Java学习笔记50(DBCP连接池)

    实际开发中,连接数据库是十分消耗资源的操作,但是,我们又需要频繁地连接数据库 这时候,为了提高效率,这里就会采用连接池技术: 连接池地通俗理解: 一个池里面放入很多的连接,需要哪一个取出来用即可,用完 ...

  2. 2、Java应用中常见的JDBC连接字符串(SQLite、MySQL、Oracle、Sybase、SQLServer、DB2)

    2.Java应用中常见的JDBC连接字符串 Java应用中连接数据库是不可或缺的,于是便整理一些可能用到的JDBC的jar包及其相匹配的URL,以备日后查阅. 1)SQLite Class.forNa ...

  3. Java开源连接池c3p0的基本用法

    前言:其实c3p0只是一个实现了javax.sql 接口 DataSource的一个工具集,使用c3p0可以帮我们管理宝贵的Connection资源,无须我们去创建连接(免去每次配置数据库驱动,url ...

  4. DBCP、C3P0、Proxool 、 BoneCP开源连接池的比《转》

     简介   使用评价  项目主页  DBCP DBCP是一个依赖Jakarta commons-pool对象池机制的数据库连接池.DBCP可以直接的在应用程序用使用 可以设置最大和最小连接,连接等待时 ...

  5. (转载)DBCP、C3P0、Proxool 、 BoneCP开源连接池的比较

    原文链接: http://blog.csdn.net/miclung/article/details/7231553    简介   使用评价  项目主页  DBCP DBCP是一个依赖Jakarta ...

  6. jdbc(1)(三)DBCP、C3P0、Proxool 、 BoneCP开源连接池的简介

     简介          使用评价  项目主页  DBCP DBCP是一个依赖Jakarta commons-pool对象池机制的数据库连接池.DBCP可以直接的在应用程序用使用 可以设置最大和最小连 ...

  7. 160629、 DBCP、C3P0、Proxool 、 BoneCP开源连接池的比较

       简介   使用评价  项目主页  DBCP DBCP是一个依赖Jakarta commons-pool对象池机制的数据库连接池.DBCP可以直接的在应用程序用使用 可以设置最大和最小连接,连接等 ...

  8. Java实战之04JavaWeb-05事务和连接池

    一.事务部分 1.事务的简介 做一件事情,这个一件事情中有多个组成单元,这个多个组成单元要不同时成功,要不同时失败.A账户转给B账户钱,将A账户转出钱的操作与B账户转入钱的操作绑定到一个事务中,要不这 ...

  9. 常见的DBCP连接池配置

    项目中使用mybatis出现一个问题,项目刚启动时,查询项目列表是ok的,过上一段时间之后,再次查询项目列表,查询失败,初步判断是因为mysql的连接问题,最后查阅资料,发现是连接池中的连接失效,导致 ...

随机推荐

  1. Python3 读写文件

    读文件 打开一个文件用open()方法(open()返回一个文件对象): >>> f = open(filename, mode,buffering) #buffering寄存,具体 ...

  2. PostgreSQL远程访问设置

    数据库版本:9.3.23(Windows xp系统) 步骤: 1.需要修改数据库安装目录下的pg_hba.conf文件 修改成: 2.并使用psql执行pg_ctl reload重新加载配置文件

  3. Servlet(六):连接数据库,完整的CRUD

    Servlet的知识点大致讲完了,今天补充下与之相关的一些小知识,然后做一个完整的小例子. 一.MVC设计模式 1.MVC设计模式是什么? 在了解MVC之前,先聊聊Model1.Model2开发模式. ...

  4. Java学习笔记--Cglib动态代理

    CGLib动态代理 使用JDK创建代理有一个限制,即它只能为接口创建代理实例,这一点可以从Proxy的接口方法newProxyInstance(ClassLoader loader,Class[] i ...

  5. 用sed实现wc -w的功能

    版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖.如要转贴,必须注明原文网址 http://www.cnblogs.com/Colin-Cai/p/7663831.html 作者:窗户 Q ...

  6. Angular路由与多视图综合案例

    Ajax请求存在的几个问题 (1)Ajax请求不会留下History 记录,会导致浏览器后退按钮失效 (2)用户无法直接通过URL进入应用中的指定页面(保存书签.链接分享给朋友) (3)Ajax对SE ...

  7. Linux中运行.sh脚本,异常/bin/sh^M: bad interpreter: No such file or directory。

    在Linux中运行.sh脚本,异常/bin/sh^M: bad interpreter: No such file or directory. 分析:这是不同系统编码格式引起的:在windows系统中 ...

  8. ubuntu18.04 递归批量删除op_test_xml/ 目录下 .pyc后缀的文件

    find op_test_xml/ -type f -name "*.pyc" -exec rm -f {} \;

  9. 性能优化——Android图片压缩与优化的几种方式

    图片优化压缩方式大概可以分为以下几类:更换图片格式,质量压缩,采样率压缩,缩放压缩,调用jpeg压缩等1.设置图片格式Android目前常用的图片格式有png,jpeg和webp,png:无损压缩图片 ...

  10. 【js】统计数组中某些项的个数

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...