“写笔记”支持四种格式——Word 文档、Excel 表格、Markdown、纯文本,起稿或二次编辑时都能随时切换,同一篇笔记想用哪种形态来记,都由你说了算。
md、txt、csv、json 这类纯文本则原样载入,不做多余加工。拿一张现成的表倒进来、改几笔、再导出去,等于白用一台免费的格式转换器。
要带走就在右上角点“下载”,可导出 PDF、Word、Markdown、Excel、TXT 等格式;列表卡片“⋯”菜单里,也有同样的下载入口。
在“工具”页点“+ 上传工具”即可发布:填好名称与链接,再用 Markdown 把使用方法写清楚——能解决什么问题、怎么装、怎么用,比堆介绍实在。
要分发安装包就一并上传压缩包(ZIP、RAR、7Z、TAR.GZ,最大 35MB),别人在详情页一键下载;只放链接不带附件也可以。
工具按大家的收藏热度排序,好用的自然会被顶上来。发布后可在详情页或卡片菜单里编辑、下架。
写笔记时勾上“隐藏”,这篇就只存在于你自己的账号里:不进列表、不进搜索、不上首页精选,也不会出现在任何公开的页面,链接发给别人同样打不开。
适合放密码、草稿、日记这类只给自己看的内容;想公开,去“发布”打开它,把“隐藏”的勾去掉再保存,之后编辑会默认保持原状态,不会悄悄变回公开。
你的内容会同时保存在多个副本上,系统定期做备份与完整性校验,再配合异地容灾机制:就算某台机器出问题,数据也不会丢,可以长期放心存放;特别重要的资料,仍建议你另外再留一份备份。
全站跑在容器化、模块化的现代架构上,更新、部署、回滚都很快,扩展性和稳定性都按长期运营的标准来设计(Built for reliability, designed to scale)。
这个网站最早只是一个人的笔记仓库,后来慢慢长成现在的知识中枢。设计上很克制——没有广告、没有追踪、没有推荐算法,只是干干净净地存放一些东西;既然做好了,就公开出来,万一有人用得上呢。
不做大而全,不做平台梦,保持简单、保持克制、保持好奇。所有内容都由用户贡献、由用户维护:不会突然冒出付费墙,不会在角落塞广告位,也不会把你的数据卖给第三方。
产品会持续迭代,站内日志页记录着每一次改动,改了什么都有迹可循;想了解这个站是怎么一步步走到今天的,翻翻日志就能看到来龙去脉。
如果在这里看到涉嫌违规的内容,点对应卡片右侧的“举报”按钮就能提交,我们会尽快核实处理;也谢谢你花一点时间,一起把这里维护干净。
JPA mybatis mybatis-plus xbatis 谁更强,比一比
最近在折腾项目选型,翻来覆去看了几个主流的 Java ORM 框架,索性把 JPA、MyBatis、MyBatis-Plus 和 Xbatis 拉出来比了一轮。没啥高大上的结论,就是记录下自己实际跑下来的感受,顺便给团队留个参考。
先说说背景
项目是标准的 Spring Boot 2.x + MySQL,单表 CRUD + 几个联表查询,数据量不大(万级别),主要对比的是:
- 开发效率(写代码快不快)
- 维护成本(改需求痛不痛)
- 动态 SQL(条件组合查询好不好搞)
- 性能(其实差距不大,但心里有数)
测试环境
- Spring Boot 2.6.3
- MySQL 8.0.28
- 表结构:一张用户表(id, name, age, email, create_time)加一张订单表(id, user_id, amount, status)
逐个分析
1. JPA (Hibernate)
优点
- 真的省代码,尤其是单表 CRUD,继承个
JpaRepository就完事了 - 方法命名查询很爽,比如
findByNameAndAge自动生成 SQL - 缓存、级联、延迟加载这些开箱即用
缺点
- 联表查询比较蛋疼,要么写 JPQL,要么用
@Query写原生 SQL - 复杂条件查询需要
Specification或者Querydsl,学习成本不低 - N+1 问题容易踩坑,不注意就炸了
代码示例
// 实体类
@Data
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private Integer age;
private String email;
private LocalDateTime createTime;
}
// 仓库接口
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByNameAndAge(String name, Integer age);
}
// 复杂查询 - 动态条件
public List<User> findByCondition(String name, Integer ageMin, Integer ageMax) {
return userRepository.findAll((Specification<User>) (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (name != null) {
predicates.add(cb.like(root.get("name"), "%" + name + "%"));
}
if (ageMin != null) {
predicates.add(cb.greaterThanOrEqualTo(root.get("age"), ageMin));
}
if (ageMax != null) {
predicates.add(cb.lessThanOrEqualTo(root.get("age"), ageMax));
}
return cb.and(predicates.toArray(new Predicate[0]));
});
}
2. MyBatis
优点
- SQL 在手,天下我有。所有 SQL 都在 mapper.xml 里,清晰可控
- 动态 SQL 用
<if><where>标签,写起来直观 - 适合 DBA 出身或者对 SQL 有执念的团队
缺点
- 太特么啰嗦了。一个简单的 CRUD 要写实体、mapper 接口、mapper.xml,还得配 resultMap
- 没有代码生成器的话,重复劳动多
- 联表查询虽然能写,但 XML 文件容易变得又长又臭
代码示例
<!-- UserMapper.xml -->
<mapper namespace="com.demo.mapper.UserMapper">
<resultMap id="userMap" type="User">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="age" property="age"/>
</resultMap>
<select id="findByCondition" resultMap="userMap">
SELECT * FROM user
<where>
<if test="name != null and name != ''">
AND name LIKE CONCAT('%', #{name}, '%')
</if>
<if test="ageMin != null">
AND age >= #{ageMin}
</if>
<if test="ageMax != null">
AND age <= #{ageMax}
</if>
</where>
</select>
</mapper>
// Mapper 接口
public interface UserMapper {
List<User> findByCondition(@Param("name") String name,
@Param("ageMin") Integer ageMin,
@Param("ageMax") Integer ageMax);
}
3. MyBatis-Plus
优点
- 继承了 MyBatis 的 SQL 控制力,又加了 JPA 式的自动 CRUD
BaseMapper自带增删改查,不用写 XMLQueryWrapper/LambdaQueryWrapper写动态条件很舒服- 分页插件、乐观锁插件、代码生成器一应俱全
缺点
- 复杂的联表查询还是得写 XML,wrapper 只适合单表
- 版本升级偶尔有坑,比如 3.x 到 3.5 有些 API 变了
- 太方便了有时候反而让人忘了 SQL 长啥样
代码示例
// Mapper 接口 - 继承 BaseMapper 就完事了
public interface UserMapper extends BaseMapper<User> {
}
// 单表 CRUD - 不用写一行 SQL
userMapper.insert(user);
userMapper.selectById(1L);
userMapper.updateById(user);
userMapper.deleteById(1L);
// 动态条件查询
LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();
wrapper.like(StringUtils.isNotBlank(name), User::getName, name);
wrapper.ge(ageMin != null, User::getAge, ageMin);
wrapper.le(ageMax != null, User::getAge, ageMax);
List<User> users = userMapper.selectList(wrapper);
// 联表查询还是得写 XML
// 但可以用 @TableName 和 @TableField 注解简化映射
4. Xbatis
Xbatis 是最近才看到的,号称“比 MyBatis-Plus 更轻量”,我简单试了试。
优点
- 确实轻,核心 jar 才几百 KB
- 支持类似 JPA 的方法命名查询
- 动态 SQL 用 Java 链式调用,不用 XML
缺点
- 社区太小,文档不全,遇到问题搜不到
- 联表查询支持一般,复杂场景容易翻车
- 没有成熟的代码生成器,得自己写
代码示例
// 实体类 - 类似 JPA 的注解风格
@XTable("user")
public class User {
@XId
private Long id;
private String name;
private Integer age;
}
// DAO 接口
public interface UserDao extends BaseDao<User> {
List<User> findByNameAndAge(String name, Integer age);
}
// 动态查询
Query query = new Query();
query.eq("name", name);
query.gt("age", ageMin);
query.lt("age", ageMax);
List<User> users = userDao.selectList(query);
横向对比
| 维度 | JPA | MyBatis | MyBatis-Plus | Xbatis |
|---|---|---|---|---|
| 单表 CRUD 效率 | ★★★★★ | ★★☆ | ★★★★★ | ★★★★ |
| 动态 SQL 灵活度 | ★★★ | ★★★★★ | ★★★★☆ | ★★★☆ |
| 联表查询 | ★★★ | ★★★★★ | ★★★★ | ★★★ |
| 学习成本 | ★★★★☆ | ★★★ | ★★★ | ★★★★ |
| 社区成熟度 | ★★★★★ | ★★★★★ | ★★★★☆ | ★★ |
| 代码量 | 少 | 多 | 少 | 中 |
我的选择建议
- 团队都是 JPA 老手,业务逻辑复杂但 SQL 简单 → JPA,别折腾了
- 团队 SQL 控,喜欢手写 SQL,需求经常变 → MyBatis-Plus,兼顾效率和灵活
- 项目简单,就几个表,想快速出活 → MyBatis-Plus 或者 JPA 都行
- 对性能有极端要求,或者 DBA 强势介入 → 原生 MyBatis,每一条 SQL 都自己控制
- Xbatis 目前不太建议生产用,除非你愿意当小白鼠
最后说两句
其实这几个框架到了实际项目里,差距真没那么大。关键还是看团队习惯和项目复杂度。我们组最后选了 MyBatis-Plus,因为:
- 单表用 wrapper 快得很
- 复杂查询写 XML 也没问题
- 代码生成器能省不少事
- 团队成员之前用过 MyBatis,上手无痛
没有银弹,只有最适合你们团队的方案。
以上测试基于个人环境,不同场景结果可能不同,仅供参考。