惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

雷峰网
雷峰网
IT之家
IT之家
Last Week in AI
Last Week in AI
J
Java Code Geeks
L
LangChain Blog
Recent Announcements
Recent Announcements
Martin Fowler
Martin Fowler
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Google DeepMind News
Google DeepMind News
博客园 - Franky
博客园 - 司徒正美
月光博客
月光博客
博客园 - 叶小钗
Vercel News
Vercel News
腾讯CDC
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
小众软件
小众软件
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
GbyAI
GbyAI
B
Blog RSS Feed
人人都是产品经理
人人都是产品经理
H
Help Net Security
G
Google Developers Blog
D
DataBreaches.Net

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Production CRUD in Java Without the Framework Tax
Z. Gao · 2026-06-18 · via DEV Community

Z. Gao

A practical walkthrough of SQL-First persistence: no XML, no Mapper interfaces, no generated queries.


I maintain a Java backend that handles ~1M requests/day. For persistence, we used to run MyBatis. The XML was manageable at first, then it wasn't. Dynamic conditions became <if> tag soup. A simple join query needed three files and two languages.

We switched to a simpler approach. Here's how it works for the most common case: single-table CRUD.

What You Need

  • Java 21+
  • Spring Boot (any 3.x)
  • A database (H2 for the demo, MySQL/PostgreSQL for production)

That's it. No XML parser, no code generator, no annotation processor.

The Project

pom.xml
src/main/java/example/
  DemoApplication.java
  user/
    User.java        -- entity
    UserDao.java     -- data access
    UserCond.java    -- query conditions
src/main/resources/
  application.yml
  schema.sql

Three Java files for a complete CRUD API.

The Entity

@Data @Builder
@Table("sys_user")
public class User {
    @Id private Long id;
    private String name;
    private Integer age;
    private String email;
    // ... other fields

    // These four are auto-managed:
    private LocalDateTime createTime;
    private Long createBy;
    private LocalDateTime updateTime;
    private Long updateBy;
    private Byte dr;  // 0 = active, 1 = soft-deleted
}

@Table maps to the database table. @Id marks the primary key (Snowflake ID by default). The audit fields and soft-delete marker are handled automatically—you don't set them in business code.

The DAO

@Repository
public class UserDao extends BaseDao<User> {
    // Empty. All CRUD methods inherited.
}

BaseDao provides save, saveBatch, update, delete, findById, list, page, count, exists. For single-table operations, this is all you need.

The Conditions

@Getter @Setter @Builder
public class UserCond extends BaseCondition {
    private String name;
    private Integer ageMin;
    private Integer ageMax;
    private Byte dr;
    private Object[] ids;

    @Override
    protected void addCondition() {
        and("name LIKE", name, 3);   // 3 = %value%
        and("age >=", ageMin);
        and("age <=", ageMax);
        and("dr =", dr);
        in("id", ids);
    }
}

Each and() line is one condition. If the parameter is null, the condition is skipped. No <if> tags, no OGNL, no XML.

The 3 in and("name LIKE", name, 3) means "wrap with % on both sides". 1 = suffix, 2 = prefix.

Running It

@Autowired UserDao userDao;

public void demo() {
    // Insert
    User user = User.builder().name("John").age(25).email("john@example.com").build();
    userDao.save(user);  // id, createTime, createBy, dr auto-filled

    // Query by ID
    User found = userDao.findById(user.getId());

    // Paginated search
    Page<User> page = userDao.page(
        UserCond.builder().name("John").ageMin(20).ageMax(30).build()
    );

    // Update
    found.setAge(26);
    userDao.update(found);  // updateTime, updateBy auto-filled

    // Soft delete (dr=1, not DELETE)
    userDao.delete(found.getId());
}

The SQL (from logs)

-- save()
INSERT INTO sys_user (id,name,age,email,create_time,create_by,dr) 
VALUES (3679201737291333632,'John',25,'john@example.com','2026-04-10 13:14:10',1000,0)

-- page()
SELECT COUNT(1) FROM sys_user t 
WHERE t.name LIKE '%John%' AND t.age >= 20 AND t.age <= 30

SELECT t.id,t.name,t.age,t.email FROM sys_user t 
WHERE t.name LIKE '%John%' AND t.age >= 20 AND t.age <= 30 
LIMIT 0,10

-- delete() with dr field present
UPDATE sys_user t SET dr=1 WHERE id IN (3679201737291333632)

The SQL in the logs is the SQL that runs. No hidden transformations, no proxy-generated queries.

What This Isn't

  • Not an ORM: We don't map object graphs or handle relationships automatically. For joins, you write the SQL.
  • Not type-safe SQL: If you misspell a column name, you find out at runtime. The tradeoff is transparency.
  • Not a replacement for everything: If you need complex caching, second-level cache, or distributed transactions, Spring has other tools.

What This Is

A thin bridge between Java and SQL. The framework handles:

  • Parameter collection and null-checking
  • Audit field auto-fill
  • Soft-delete logic
  • Pagination (count + limit)

You handle:

  • The SQL
  • The business logic
  • The optimization

Next

Episode 02: Multi-table joins with the same API → [link]

Full source: github.com/gzz2017gzz/simple-dao-demo