JDO 示例 - JPOX

(ALin 2006-12-27 00:28)

第一部分:相关概念
[JDO 的实现版本之一: JPOX]
JPOX 是 JDO 的一个具体实现版本。其官方主页为: http://www.jpox.org/index.jsp
JDO 现在是 2.0 版,以前的 1.0 版的 Sun 官方有具体的实现,不过后来移交给 Apache 了,所以 Apache 网站上也有 JDO 的实现。这种标准的 API 加上具体的实现的方式在 Java 相关技术中很常见。下载 JPOX1.1.4 版。
[ 可持久化类 ]
JDO 规范定义了作为 Java 接口的可持久约定,称之为 PersistenceCapable ,同时还定义了类实现必须遵守的编程风格。遵守该约定的类被定义为是“可持久的”。 JOD 作为一种 ORM 解决方案,使用 JDO 可以有 3 种方法生成可持久类:

1.     源代码生成,即是实现相关的接口,自己编写相关的方法,在点类似于BMP EJB。

2.     源代码处理。

3.     字节码增强(使用字节码增强工具:byte-code enhancer)。

JDO 要求可持久类必须有一个不带参数的构造函数,可以是 public, protected, private, 只要保证定义的类及其潜在的子类能够访问即可。
[JDO 元数据 ]
JDO 无数据即是描述可持久化类与数据库相互关系的文件,是以 jdo 为扩展名 XML 文件。假如有一个类为:
alin.scut.jdo.Author ,则描述该类的元数据可以在以下文件中:

Ø         package.jdo

Ø         alin/package.jdo

Ø         alin/scut/package.jdo

Ø         alin/scut/jdo/package.jdo

Ø         alin/scut/jdo/Author.jdo

按以上顺序搜索元数据,并使用第一个发现的定义。
[JDO 配置文件 ]
和其他的 ORM 框架一样, JDO 也有一个配置文件,具体的实现可能有不同的配置文件。 JPOX 的配置文件为: jpox.properties ,作用和 Hibernate 的 hibernate.cfg.xml 文件类似。同时,还应该为 JPOX 提供一个 Log4j 的配置文件,用来输出日志。
第二部分:示例
这个例子只简单地示范可持久化类的创建、删除、更新和查询,不涉及关系部分。当然,为了直观起见,照样不使用 IDE ,而使用简单的文本编辑器和相关的命令行工具。
一、 建立本项目的目录结构,本项目中一共只有一个可持久类, alin.demo.Author 。项目的根文件夹下面一共 3 个文件夹: bin, src, lib 。具体各个目录放置什么地球人都知道吧!?
lib 目录下的 JAR 文件就是 JDO2.0 的标准 API 和 JPOX 的实现,由于使用到 Log4j ,因此还要把 Log4j 的 JAR 文件也放到此目录下。最终的目录结构如下:
<Project>
lib
jdo.jar( 或者叫 jdo2-api.jar)
JDO2.0 AIPI
jpox.jar
JPOX1.1.4 实现
jpox-enhancer.jar
JPOX 的字节码增强器
log4j.jar
Log4j
bcel.jar
(jboss-4.0.2/server/default/lib 目录下面有 )
Byte Code Engineering Library
 (BCEL) ,这是 Apache Software
 Foundation 的 Jakarta 项目的一部分。
src
alin/demo/Author.java
alin/main/ …… .java
这个包下面的源文件是示例应用程序
alin/demo/Author.jdo
jpox.properties
注意数据库 URL 后面部分的作用:
SelectMethod=cursor( 后面会说明 )
log4j.properties
bin
alin/demo/Author.class
alin/main/ …… .class
alin/demo/Author.jdo
这些文件都是直接从 src 目录下面复制过来的。
jpox.properties
log4j.properties
二、各文件具体内容:
(1) 可持久类 Author.java

代码1: Author.java

// Author.java -- Demostrate JDO.
// 2006-11-25 20:55
package alin.demo;
//import javax.jdo.spi.PersistenceCapable;
//import javax.jdo.JDOHelper;
public class Author {

private int books;

private String name;

  

public Author(String name, int books) {

this.name = name;

this.books = books;

   }
  

protected Author() {

   }

public String getName() {

return name;

   }

public void setName(String name) {

this.name = name;

   }

public int getBooks() {

return books;

   }

public void setBooks(int books) {

this.books = books;

   }
}
(2) 元数据文件
代码 2 : Author.jdo

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE jdo PUBLIC

"-//Sun Microsystems, Inc.//DTD Java Data Objects Metadata 2.0//EN"

"http://java.sun.com/dtd/jdo_2_0.dtd">

<jdo>

<package name="alin.demo">

<class name="Author" identity-type="datastore">

<field name="books" persistence-modifier="persistent">

</field>

<field name="name" persistence-modifier="persistent">

<column length="50" jdbc-type="VARCHAR"/>

</field>

       </class>
   </package>
</jdo>
(3)JPOX 配置文件,注意这个属性: javax.jdo.PersistenceManagerFactoryClass ,代表的是 JDO 的 PersistenceManagerFactory 的具体实现,这个值依赖于具体的实现。前面的一组属性是 JDO 的标准属性,任何实现都必须支持的,后面的是 JPOX 的扩展属性。
代码 3 : jpox.properties
# jpox.properties -- jpox configuration.
# 2006-11-28 19:24
# -- Standard JDO properties. --
javax.jdo.PersistenceManagerFactoryClass=org.jpox.PersistenceManagerFactoryImpl
javax.jdo.option.ConnectionDriverName=com.microsoft.jdbc.sqlserver.SQLServerDriver
javax.jdo.option.ConnectionURL=jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=JDO;SelectMethod=cursor
javax.jdo.option.ConnectionUserName=sa
javax.jdo.option.ConnectionPassword=sqlserversaps
# -- JPOX properties. --
org.jpox.autoCreateSchema=true
org.jpox.validateTables=false
org.jpox.validateConstraints=false
(4) log4j 配置文件
代码 4 : log4j.properties
# LOG4J Configuration
# ===================
# Basic logging goes to "jpox.log"
log4j.appender.A1=org.apache.log4j.FileAppender
log4j.appender.A1.File=jpox.log
log4j.appender.A1.layout=org.apache.log4j.PatternLayout

log4j.appender.A1.layout.ConversionPattern=%d{HH:mm:ss,SSS} (%t) %-5p [%c] - %m%n

#log4j.appender.A1.Threshold=INFO
# Categories

# Each category can be set to a "level", and to direct to an appender

#log4j.rootCategory=INFO, A1
log4j.category.JPOX.JDO=DEBUG, A1
log4j.category.JPOX.Cache=DEBUG, A1
log4j.category.JPOX.MetaData=DEBUG, A1
log4j.category.JPOX.General=DEBUG, A1
log4j.category.JPOX.Utility=DEBUG, A1
log4j.category.JPOX.Transaction=DEBUG, A1
log4j.category.JPOX.Store.Poid=DEBUG, A1
log4j.category.JPOX.RDBMS=DEBUG, A1

# Commented out sub-categories since the above setting applies to all subcategories

#log4j.category.JPOX.RDBMS.Schema=DEBUG, A1
#log4j.category.JPOX.RDBMS.DDL=DEBUG, A1
#log4j.category.JPOX.RDBMS.SQL=DEBUG, A1
log4j.category.JPOX.ClassLoading=INFO, A1
log4j.category.JPOX.Plugin=DEBUG, A1
log4j.category.JPOX.Enhancer=DEBUG, A1
log4j.category.JPOX.SchemaTool=DEBUG, A1
log4j.category.JPOX.TEST=DEBUG, A1
#
# C3P0 logging
#
log4j.category.com.mchange.v2.c3p0=INFO, A1

log4j.category.com.mchange.v2.resourcepool=INFO, A1

#
# Proxool logging
#
log4j.category.org.logicalcobwebs.proxool=INFO,A1
这个文件是个什么意思我也不太清楚。
三、把编译后的类文件正确放到 bin 目录下。进行一下步工作:字节码增强。 JPOX 的字节码增强工具主类为: org.jpox.enhancer.JPOXEnhancer 。
使用方法 ( 在项目的 bin 目录下运行 ) :

java org.jpox.enhancer.JPOXEnhancer alin/jpox/package.jdo

这里有个问题了,因为 org.jpox.enhancer.JPOXEnhancer 不在标准的 Java 类库中,而在 jpox-enhancer.jar 包中,因此呢要加上 cp 参数才能正确的运行。我自己直接把 lib 目录下面的包放置到了 Java 的 2 个扩展包目录 (ext 目录, JDK 下有一个, JRE 下面有一个,两个都要放才能正确编译和运行 ) 下面,就可以直接像上面那样进行字节码增强。
一切正常的话应该会看到如下的输出:

JPOX Enhancer completed with success for 2 classes. Consult the log for full details

字节码增强后要进行的工作是:生成数据库 Schema ,即创建可持久化类对应的数据库表。使用如下命令进行 ( 同样在 bin 目录下进行 ) :

java org.jpox.SchemaTool -props jpox.properties -create alin/jpox/package.jdo

最终会看到如下的输出:
代码 5 :生成数据库 Schema 时的输出

JPOX SchemaTool (version 1.1.4) : Creation of the schema

2006-11-28 19:29:52 org.jpox.util.JDK14Logger info

信息: PersistenceManagerFactory - Vendor: JPOX Version: 1.1.4

2006-11-28 19:29:52 org.jpox.util.JDK14Logger info

信息: PersistenceManagerFactory initialised for datastore URL=jdbc:microsoft:sql

server://localhost:1433;DatabaseName=JDO driver=com.microsoft.jdbc.sqlserver.SQL

ServerDriver userName=sa

2006-11-28 19:29:53 org.jpox.util.JDK14Logger info

信息: ================ DatabaseAdapter ==================

2006-11-28 19:29:53 org.jpox.util.JDK14Logger info

信息: Adapter : org.jpox.store.rdbms.adapter.MSSQLServerAdapter

2006-11-28 19:29:53 org.jpox.util.JDK14Logger info

信息: Datastore : name="Microsoft SQL Server" version="Microsoft SQL Server 200

0 - 8.00.2039 (Intel X86)

May 3 2005 23:18:38

Copyright (c) 1988-2003 Microsoft Corporation

Developer Edition on Windows NT 5.1 (Build 2600: Service Pack 2)

" (major=2000, minor=0, revision=-1)

2006-11-28 19:29:53 org.jpox.util.JDK14Logger info

信息: Driver : name="SQLServer" version="2.2.0022" (major=2, minor=2)

2006-11-28 19:29:53 org.jpox.util.JDK14Logger info

信息: ===================================================

2006-11-28 19:29:53 org.jpox.util.JDK14Logger info

信息: Initialising Catalog "JDO", Schema "" using "None" auto-start option

2006-11-28 19:29:53 org.jpox.util.JDK14Logger info

信息: Catalog "JDO", Schema "" initialised - managing 0 classes

2006-11-28 19:29:53 org.jpox.util.JDK14Logger warn

警告: No manager for annotations was found in the CLASSPATH so all annotations a

re ignored.

2006-11-28 19:29:53 org.jpox.util.JDK14Logger info

信息: Managing Persistence of Class : alin.jpox.Product [Table : PRODUCT, Inheri

tanceStrategy : new-table]

2006-11-28 19:29:53 org.jpox.util.JDK14Logger info

信息: Managing Persistence of Class : alin.jpox.Book [Table : BOOK, InheritanceS

trategy : new-table]

2006-11-28 19:29:53 org.jpox.util.JDK14Logger info

信息 : Creating table BOOK

2006-11-28 19:29:53 org.jpox.util.JDK14Logger info

信息 : Creating table PRODUCT

2006-11-28 19:29:54 org.jpox.util.JDK14Logger info

信息 : Validated 1 unique key(s) for table BOOK

2006-11-28 19:29:54 org.jpox.util.JDK14Logger info

信息: Creating foreign key constraint : "BOOK_FK1" in catalog "" schema ""

2006-11-28 19:29:54 org.jpox.util.JDK14Logger info

信息 : Validated 1 index(es) for table BOOK

2006-11-28 19:29:54 org.jpox.util.JDK14Logger info

信息: Validated 1 unique key(s) for table PRODUCT

2006-11-28 19:29:54 org.jpox.util.JDK14Logger info

信息 : Validated 1 index(es) for table PRODUCT

2006-11-28 19:29:54 org.jpox.util.JDK14Logger info

信息 : SchemaTool completed successfully
SchemaTool completed successfully
四、  示例 JDO 用法。
(1) 持久化一个 Author 。
代码 6 : MakePersistent.java

// MakePersistent.java -- Create an Author object and persist it.

// 2006-11-29 10:32
package alin.main;
import javax.jdo.*;
import alin.demo.*;

public class MakePersistent {

   public static void main(String[] args) {
       PersistenceManagerFactory pmf =
           JDOHelper.getPersistenceManagerFactory("jpox.properties");

PersistenceManager pm = pmf.getPersistenceManager();

       Transaction tx = pm.currentTransaction();
       tx.begin();

Author au = new Author("Eric Ben", 5);

System.out.println("Author: " + au.getName() + "/t" + au.getBooks()

               + " Books");
      
       pm.makePersistent(au);
       tx.commit();
//     tx.rollback();
      

//     Can not read fields outside of transactions. Or set:

//     pmf.setNontransactionalRead(true);

//     System.out.println("Author: " + au.getName() + "/t" + au.getBooks()

//             + " Books");
       tx.begin();
       String name = au.getName();

System.out.println("Author: " + name);

       tx.commit();
      
       pm.close();
       pmf.close();
   }
}
所有的 JDO 应用程序基本的代码框架应该像下面这个样子:

// MakePersistent.java -- Create an Author object and persist it.

// 2006-11-29 10:32
package alin.main;
import javax.jdo.*;
import alin.demo.*;
public class MakePersistent {

public static void main(String[] args) {

PersistenceManagerFactory pmf =

            JDOHelper.getPersistenceManagerFactory("jpox.properties");

PersistenceManager pm = pmf.getPersistenceManager();

Transaction tx = pm.currentTransaction();

        tx.begin();

// Do other things.

        tx.commit();
//      tx.rollback();
       
        pm.close();
        pmf.close();
    }
}
通过 JDOHelper 获得一个 PersistenceManagerFactory(PMF) ,提供配置文件即可,可以参考具体 API 文档查看相关的方法。再通过 PMF 得到 PersistenceManager(PM) 。只有在事务提交后才会真正写入到数据库中,如果事务回滚,则会丢弃所做的更改。
(2) 删除指定名字的第一个 Author 。
代码 7 : DeleteExample.java
// DeleteExample.java -- Delete an Author.
// 2006-11-29 16:26
package alin.main;
import java.util.Collection;
import javax.jdo.JDOHelper;
//import javax.jdo.JDOUserException;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.Query;
import javax.jdo.Transaction;
import alin.demo.Author;
public class DeleteExample {

public static void main(String[] args) {

PersistenceManagerFactory pmf = JDOHelper

               .getPersistenceManagerFactory("jpox.properties");

PersistenceManager pm = pmf.getPersistenceManager();

Transaction tx = pm.currentTransaction();

       tx.begin();

Query query = pm.newQuery(Author.class, "name == /"Eric Ben/"");

Collection result = (Collection)query.execute();

Author au = null;

if(result.iterator().hasNext()) {

au = (Author)(result.iterator().next());

       }
       query.close(result);

// query.closeAll();

if(au == null) {

System.out.println("No Author found!");

           System.exit(1);
       }
       pm.deletePersistent(au);
      

// Can npt read fields from deleted objects. So this statement below

// will throws Runtime Exception: JDOUserException.

// System.out.println(au.getName());

      

// If we don't want update, we can use tx.rollback() instead of

// tx.commit()

       tx.commit();
       tx.begin();
      

String name = au.getName();

System.out.println("Author: " + name + " |/t" + au.getBooks());

  
       tx.commit();
       pm.close();
       pmf.close();
   }
}

Query query = pm.newQuery(Author.class, "name == /"Eric Ben/"");这一句创建了一个查询,第二个参数是JDO QL语句,具体语法这里不说了,较多。有的实现可以设置成使用SQL语句。

查询执行返回的是一个集合,集合为空表示没有任何结果。
(3) 更新示例
代码 8 : UpdateExample.java
// UpdateExample.java -- Update.
// 2006-11-29 16:11
package alin.main;
import java.util.Collection;
import javax.jdo.*;
import alin.demo.*;
public class UpdateExample {

public static void main(String[] args) {

PersistenceManagerFactory pmf = JDOHelper

               .getPersistenceManagerFactory("jpox.properties");

PersistenceManager pm = pmf.getPersistenceManager();

Transaction tx = pm.currentTransaction();

       tx.begin();

Query query = pm.newQuery(Author.class, "name == /"WeiQin Sun/"");

Collection result = (Collection) query.execute();

Author au = null;

if (result.iterator().hasNext()) {

au = (Author) (result.iterator().next());

       }
       query.close(result);

// query.closeAll();

      

if(au == null) {

System.out.println("No Author named [WeiQin Sun] found!");

           System.exit(1);
       }

au.setName("Jie Hou");

// If we don't want update, we can use tx.rollback() instead of

// tx.commit()

       tx.commit();
       tx.begin();

String name = au.getName();

System.out.println("Author: " + name + " |/t" + au.getBooks());

       tx.commit();
      
       pm.close();
       pmf.close();
   }
}
(4) 查询示例, JDO 中一共可以按照 3 种方式读取对象:

Ø         使用导航

Ø         Extent查询,Extent代表某个可持久类的所有实例(可以包括其子类)

Ø         Query查询,Query则代表满足一些条件的实例,如叫某个特定名字

使用导航大致是个什么意思呢?就是说如果已经在数据库在查询得出了一个 Author 对象,而 Author 有一个 String 属性,对应也有一个对象,我就使用 Author 对象的引用即可得到 String 对象。像下面这样,假设已经查询取得了 author 对象。
tx.begin();

String name = author.getName(); // author是导航引用

……
tx.commit();
通过 2 个例子来分别示范 Extent 和 Query 查询方式。
代码 9 : ReadExtent.java

// ReadExtent.java -- Read by Extent.

// 2006-11-29 15:56
package alin.main;

import java.util.Iterator;

import javax.jdo.*;
import alin.demo.*;

public class ReadExtent {

   public static void main(String[] args) {
       PersistenceManagerFactory pmf =
           JDOHelper.getPersistenceManagerFactory("jpox.properties");

PersistenceManager pm = pmf.getPersistenceManager();

       Transaction tx = pm.currentTransaction();
       tx.begin();
      
       // 参数 false 表示不包括子类的实例

Extent extent = pm.getExtent(Author.class, false);

       Iterator itor = extent.iterator();
       Author au;
       while(itor.hasNext()) {
           au = (Author)itor.next();

System.out.println("Author: " + au.getName() + " |/t"

                   + au.getBooks());
       }
       extent.close(itor);
       tx.commit();
      
       pm.close();
       pmf.close();
   }
}
代码 10 : ReadQuery.java
// ReadQuery.java -- Read by Query.
// 2006-11-29 16:05
package alin.main;
import java.util.Collection;
import java.util.Iterator;
import javax.jdo.*;
import alin.demo.*;
public class ReadQuery {

public static void main(String[] args) {

PersistenceManagerFactory pmf =

           JDOHelper.getPersistenceManagerFactory("jpox.properties");

PersistenceManager pm = pmf.getPersistenceManager();

Transaction tx = pm.currentTransaction();

       tx.begin();

Query query = pm.newQuery(Author.class, "books == 5");

Collection result = (Collection)query.execute();

Iterator itor = result.iterator();

Author au;

while(itor.hasNext()) {

au = (Author)itor.next();

System.out.println("Author: " + au.getName() + " |/t"

+ au.getBooks());

       }
       query.close(result);
       tx.commit();
      
       pm.close();
       pmf.close();
   }
}
五、可能错误情况:

出现:Can't start a cloned connection while in manual transaction mode

原因一般是当你在一个 SQL SERVER 的 JDBC 连接上执行多个 STATEMENTS 的操作,或者是手动事务状态( AutoCommit=false) 并且使用 direct (SelectMethod=direct) 模式 .
Direct 模式是默认的模式 .
解决办法:
当你使用手动事务模式时,必须把 SelectMethod 属性的值设置为 Cursor, 或者是确保在你的连接只有一个 STATEMENT 操作。
修改 url ,加入 SelectMethod=cursor 即可
例:原来为:
jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=JDO
修改后为:
jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=JDO;SelectMethod=cursor
[ 参考资料 ]
1. 《 JOD 核心技术》,本文的代码大部分都是参考本书上面的代码。
2. JPOX 文档,官方主页有相关链接。

JDO示例 - JPOX相关推荐

  1. Hive 快速上手--官网中文翻译

    目录 安装和配置 从一个稳定的发行版安装Hive 编译Hive源码 编译主干的Hive 编译分支branch-1 在Hadoop 0.20上在0.13之前编译Hive 在Hadoop 0.23上在0. ...

  2. 转载:使用Spring进行数据访问(Data Access With Spring)

    Table of Contents 1.1. 统一的数据访问异常层次体系(Consistent Exception Hierarchy In Spring) 1.1.1. DAO模式的背景(Backg ...

  3. DataNucleus之JDO操作示例

    JDO(Java Data Object )是Java对象持久化的新的规范,也是一个用于存取某种数据仓库中的对象的标准化API.注意JDO是一种规范,而不是一个产品.而DataNucleus正是实现J ...

  4. Google App Engine + JDO + Spring MVC,CRUD示例

    注意 本教程更多关于实践指南,请参考此官方的在数据存储区中使用JDO了解详细说明. 请参阅以下代码段,以使用Java数据对象(JDO)在GAE数据存储上执行CRUD. 只需使用JDO注释为客户注释,然 ...

  5. Java数据对象(JDO)快速入门

    JDO有一个充满活力的社区.所以如果你正在为你的POJO寻找持久化 解决方案,JDO是一个通过JCP项目开发的标准.JDO为POJO持久化提供了一个丰富和具有全部特征的JSR规范,并且很多开发商正在提 ...

  6. Spring事务管理示例JDBC

    Spring事务管理示例JDBC Spring Transaction Management是Spring框架中使用最广泛且最重要的特性之一.事务管理在任何企业应用程序中都是一项微不足道的任务.我们已 ...

  7. spring事务 jdbc_Spring事务管理示例JDBC

    spring事务 jdbc Spring Transaction Management is one of the most widely used and important feature of ...

  8. DataNucleus JDO基础入门

    开发应用程序通常是一项复杂的任务,涉及许多组件. 开发所有这些组件可能非常耗时. Java 数据对象 API (JDO) 旨在减少花费的一些时间,提供一个 API 以允许 Java 开发人员将面向对象 ...

  9. JDO持久框架——DataNucles

    1. JDO框架简介 Java数据对象(Java Data Objects,JDO)是一个应用程序接口(API),它是Java程序员能够间接地访问数据库,也就是说,不需使用直接的结构化查询语言(SQL ...

最新文章

  1. python使用matplotlib可视化折线图、在可视化图像中同时绘制多条折线图
  2. mysql 查询缓存
  3. 安卓三维展示源码_手机(安卓)自动化脚本开发线上培训
  4. 使用SecureCRT脚本备份网络设备配置的一点感悟
  5. remote vscode无git_vs code 使用git
  6. java 除法向上,向下取整
  7. LoudMiner:伪装在VST软件中的跨平台挖矿软件
  8. 《黑客X档案2007配套光盘》2007年上半年合集(6期)
  9. MATLAB Simulink工具箱
  10. html怎么显示五线谱,教你一个怎么看五线谱的绝招!
  11. 东方时尚驾校科目一网上视频快速通过方法
  12. 关于侵权Sinesafe官方网站,仿冒、抄袭等恶劣行为的公告
  13. 由于哈希冲突,不同值的对象也可能具有相同的哈希值
  14. 使用HBuilder制作一个简单的HTML5动漫网页——紫罗兰永恒花园动漫价绍网页 7页
  15. Editor\Data\il2cpp/build/deploy/net471/il2cpp.exe did not run properly!
  16. {电脑救助站}常用知识1 来自常用知识( 网络安全中起重大作用的 Windows 命令)
  17. 通过css和js实现流星雨效果
  18. 作者:​孙少陵(1972-),男,中移(苏州)软件技术有限公司高级工程师、副总经理。...
  19. latex 大于小于大于等于小于等于
  20. React类式组件基础内容补充

热门文章

  1. ipad协议720版本
  2. Day50 python 多表操作
  3. CSS学习笔记(学习中)
  4. TEST1笔记 200408
  5. AcFun 的视频架构演化实践阅读心得
  6. 大页面内存引起的杯具
  7. git push /git pul 每次都要输入账号密码问题
  8. HTML+CSS+JavaScript制作登录页面_科幻后台登录界面html模板_科技感登录界面html模板
  9. pycharm申请学生账号收不到邮件问题(不是你收不到而是你没找到,邮件被拦截了)
  10. win10怎么还原系统【系统天地】