02-Servlet、JDBC、Maven、Mybatis

一、servlet

Servlet 是 Java 处理 HTTP 请求的规范。浏览器发请求 → Servlet 接收处理 → 返回响应。

1. 生命周期

scss 复制代码
加载类
实例化(new Servlet)
init()  //初始化,只执行一次
service()  //每次请求都执行
   └── doGet()+ doPost()
destroy()    //销毁,只执行一次

2.案例

Java 复制代码
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter out = resp.getWriter();
        out.println("<h1>Hello Servlet</h1>");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
        String username = req.getParameter("username");
        resp.setContentType("text/html;charset=UTF-8");
        resp.getWriter().println("你好," + username);
    }
}

二、jdbc

JDBC (Java Database Connectivity)是 Java 访问数据库的标准 API

1.执行步骤

Java 复制代码
// 1. 加载驱动(JDBC 4.0+ 可省略,驱动 jar 在 classpath 即可)
Class.forName("com.mysql.cj.jdbc.Driver");

// 2. 获取连接
String url = "jdbc:mysql://localhost:3306/mybatis_demo?useSSL=false&serverTimezone=Asia/Shanghai";
Connection conn = DriverManager.getConnection(url, "root", "密码");

// 3. 编写 SQL
String sql = "SELECT id, username, email FROM user WHERE id = ?";

// 4. 创建 PreparedStatement
PreparedStatement ps = conn.prepareStatement(sql);
ps.setLong(1, 1L);  // 第 1 个 ? 设为 1

// 5. 执行查询
ResultSet rs = ps.executeQuery();

// 6. 处理结果
while (rs.next()) {
    long id = rs.getLong("id");
    String username = rs.getString("username");
    String email = rs.getString("email");
    System.out.println(id + ", " + username + ", " + email);
}

// 7. 关闭资源(顺序:后开先关)
rs.close();
ps.close();
conn.close();

2.案例

如下可以看到JDBC操作数据库需要编写sql代码,结果需手动映射到Java对象。

Java 复制代码
import java.sql.*;

public class JdbcDemo {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/mybatis_demo?useSSL=false&serverTimezone=Asia/Shanghai";
        String sql = "SELECT id, username, email, age FROM user WHERE id = ?";

        try (Connection conn = DriverManager.getConnection(url, "root", "");
             PreparedStatement ps = conn.prepareStatement(sql)) {

            ps.setLong(1, 1L);
            ResultSet rs = ps.executeQuery();

            if (rs.next()) {
                System.out.println("id=" + rs.getLong("id"));
                System.out.println("username=" + rs.getString("username"));
                System.out.println("email=" + rs.getString("email"));
                System.out.println("age=" + rs.getInt("age"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

三、maven

maven是Java的构建与依赖管理工具,类似前端的webpack工具

1.pom.xml

pom.xml是maven最重要的配置文件,其内部定义了项目配置与依赖管理配置。

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project>
    <modelVersion>4.0.0</modelVersion>

    <!-- 本项目坐标 -->
    <groupId>org.example</groupId>
    <artifactId>mybatis-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- 全局属性 -->
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <!-- 依赖列表 -->
    <dependencies>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>8.3.0</version>
        </dependency>
    </dependencies>
</project>

2.目录结构

css 复制代码
mybatis-demo/
├── pom.xml Maven 配置文件
├── src/
│   ├── main/
│   │   ├── java/Java 源码
│   │   └── resources/ 配置文件(xml、yml)
│   └── test/
│       ├── java/测试代码
│       └── resources/
└── target/ 编译输出(自动生成,勿提交 Git)

四、mybatis

mybatis解决了jdbc操作数据库时编写大量样板间代码的缺陷。把数据库连接,增删改查等操作全部配置在xml文件。

1.结构组成

css 复制代码
src/main/java/org/example/
├── entity/              ← 实体类(和数据库表对应)
│   ├── User.java
│   ├── Department.java
│   └── Order.java
├── mapper/              ← Mapper 接口(定义数据库操作方法)
│   └── UserMapper.java
└── Main.java            ← 程序入口(测试用)

src/main/resources/
├── mybatis-config.xml ← 全局配置
├── mapper/
│ └── UserMapper.xml ← SQL 映射文件
  • 1.mybatis-config.xml:保存mybatis基础配置与mapper映射
Java 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 开启驼峰命名自动映射:create_time → createTime -->
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <typeAliases>
        <package name="org.example.entity"/>
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url"
                          value="jdbc:mysql://localhost:3306/mybatis_demo?useSSL=false&amp;serverTimezone=Asia/Shanghai"/>
                <property name="username" value="root"/>
                <property name="password" value=""/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!-- XML 放在 resources/mapper/ 下,需显式注册 -->
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
</configuration>
  • 2.实体类(entity目录)

实体类定义了其数据库对象的映射表,例如user表格包含id,name,age字段,那我们的实体对象必须定义这几个属性,并添加get、set、重写equals方法。

Java 复制代码
package org.example.entity;

import java.time.LocalDateTime;
import java.util.List;

public class User {
  private Long id;
  private String username;
  private String password;

  public Long getId() {
    return id;
  }

  public void setId(Long id) {
    this.id = id;
  }

  public String getUsername() {
    return username;
  }

  public void setUsername(String username) {
    this.username = username;
  }

  public String getPassword() {
    return password;
  }

  public void setPassword(String password) {
    this.password = password;
  }

  @Override
  public String toString() {
   return "xxx"
  }
}
  • 3.xml文件(SQL映射)

UserMapper.xml保存了User表的所有数据库操作,其中namespace属性定义其xml文件的路径,id标记了唯一的数据库操作语句。

Java 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
        
<mapper namespace="org.example.mapper.UserMapper">
    <select id="findAll" resultType="User">
        SELECT * FROM user WHERE 1=1
    </select>

</mapper>
  • 4.mapper目录

mapper目录下定义操作数据库的接口方法,其方法名和xml数据库操作的id一一映射。

java 复制代码
package org.example.mapper;

import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.example.entity.User;
import java.util.List;

public interface UserMapper {
    List<User> findAll();
}
  • 5.入口配置
Java 复制代码
package org.example;

import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.example.mapper.UserMapper;
import org.example.entity.User;
import java.util.List;
import java.util.Scanner;
public class Main {
    public static void main(String[] args) throws IOException {
        // 1. 加载配置文件
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        // 2. 构建 SqlSessionFactory
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        // 3. 获取 SqlSession
        try (SqlSession session = factory.openSession();
             Scanner scanner = new Scanner(System.in)) {
            // 4. 获取 Mapper 代理对象
            UserMapper mapper = session.getMapper(UserMapper.class);
            // 5. 执行查询
            List<User> users = mapper.findAll();  
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2. XML文件

2.1 增删改查

mybatis为数据库操作添加了4种标签,增删改查。

sql 复制代码
<select id="findById" resultType="User">
    SELECT * FROM user WHERE id = #{id}
</select>


<insert id="insert" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO user (username, password, email, age)
    VALUES (#{username}, #{password}, #{email}, #{age})
</insert>

2.2 参数传递

标签的值传递通过#{xx}进行传递。

  1. 简单的id查询
sql 复制代码
User findById(Long id);

<select id="findById" resultType="User">
    SELECT * FROM user WHERE id = #{id}
</select>
  1. 多个参数操作

大于等于2个参数传递时,必须使用@Param("xxx")进行标记,param里面的名称与xml参数名一致

less 复制代码
List<User> findByUsernameAndAge(@Param("username1") String username, @Param("age1") Integer age);

<select id="findByUsernameAndAge" resultType="User">
     SELECT * FROM user WHERE username = #{username1} AND age = #{age1}
 </select>
  1. 参数解构

如果接口中的参数是实例对象,那xml的标签可以自动读取到对象的属性

sql 复制代码
List<User> findByUsernameAndAge(User user);

<select id="findByUsernameAndAge" resultType="User">
     SELECT * FROM user WHERE username = #{username} AND age = #{age}
 </select>

2.3 注解

mybatis的数据库查询有两种,1种是上面的接口与xml分离,第二种就接口中直接定义注解实现。实际项目中简单sql查询用注解,复杂sql用分离

Java 复制代码
package org.example.mapper;

import org.apache.ibatis.annotations.*;
import org.example.entity.User;
import java.util.List;

public interface UserAnnotationMapper {

    @Select("SELECT * FROM user WHERE id = #{id}")
    User findById(Long id);

    @Select("SELECT * FROM user")
    List<User> findAll();

    @Insert("INSERT INTO user (username, password, email, age) " +
            "VALUES (#{username}, #{password}, #{email}, #{age})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insert(User user);

    @Update("UPDATE user SET email = #{email}, age = #{age} WHERE id = #{id}")
    int update(User user);

    @Delete("DELETE FROM user WHERE id = #{id}")
    int deleteById(Long id);
}

2.4 动态SQL

在操作sql时,如果需要针对不同的条件进行增删改查,当条件数量很多时,需要定义大量重复的条件xml和方法,为此引入了动态sql。

2.4.1 if标签

如下表示查询username,age、email等多种情况。

Java 复制代码
// xml
<select id="findByCondition" resultType="User">
    SELECT * FROM user
    WHERE 1=1
    <if test="username != null and username != ''">
        AND username = #{username}
    </if>
    <if test="age != null">
        AND age = #{age}
    </if>
    <if test="email != null and email != ''">
        AND email = #{email}
    </if>
</select>


//接口
 List<User> findByCombine(User user);
 
 //main
 List<User> users = mapper.findByCombine(user);

2.4.2 Where

where标签省略了上面的where 1=1的操作

bash 复制代码
<select id="findByCondition" resultType="User">
    SELECT * FROM user
    <where>
        <if test="username != null and username != ''">
            AND username = #{username}
        </if>
        <if test="age != null">
            AND age = #{age}
        </if>
    </where>
</select>

2.4.3 choose

choose标签类似java的switch表达式

sql 复制代码
<select id="findByAgeRange" resultType="User">
    SELECT * FROM user
    <where>
        <choose>
            <when test="ageRange == 'young'">
                AND age < 30
            </when>
            <when test="ageRange == 'middle'">
                AND age BETWEEN 30 AND 50
            </when>
            <otherwise>
                AND age > 50
            </otherwise>
        </choose>
    </where>
</select>

2.4.4 foreach

foreach标签用于批量操作。

sql 复制代码
<select id="findByIds" resultType="User">
    SELECT * FROM user WHERE id IN
    <foreach collection="ids" item="id" open="(" separator="," close=")">
        #{id}
    </foreach>
</select>

//接口中定义

List<User> findByIds(@Param("ids") List<Long> ids);

2.4.5 trim

trim标签用于在动态 SQL 片段外面加前缀/后缀,并去掉多余的符号(通常是逗号)。

属性 含义 例子
prefix 在最前面加什么 ( → 变成 (name, description
suffix 在最后面加什么 ) → 变成 (name, description)
prefixOverrides 去掉开头多余内容 ANDOR
suffixOverrides 去掉结尾多余内容 ,

如下是一段插入的sql表达式 insert into category (name,description) values (xx,xx)

Java 复制代码
INSERT INTO category
<trim prefix="(" suffix=")" suffixOverrides=",">
    <if test="name != null">name,</if>
    <if test="description != null">description,</if>
</trim>
<trim prefix="VALUES (" suffix=")" suffixOverrides=",">
    <if test="name != null">#{name},</if>
    <if test="description != null">#{description},</if>
</trim>

2.5 结果映射

resultType还能用于sql简单查询,数据库的表格字段与对象的属性完全一致。但复杂场景或者多表关联时就必须引入结果映射resultMap了。

2.5.1 基础结构

其中property表示User类的属性,column表示映射sql查询时用到的变量。

ini 复制代码
<resultMap id="UserResultMap" type="User">
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <result property="email" column="email"/>
    <result property="age" column="age"/>
    <result property="createTime" column="create_time"/>
</resultMap>

<select id="findById" resultMap="UserResultMap">
    SELECT id, username, email, age, create_time FROM user WHERE id = #{id}
</select>

2.6 关联查询

关联查询即数据库中的多表操作。需要使用association或者collection标签关联。如果是1对1关系使用association,1对多关系用collection。

案例是在user属性有个order\[\]数组,也就是1对多存储

ini 复制代码
<resultMap id="UserWithOrdersMap" type="User">
    <id property="id" column="user_id"/>
    <result property="username" column="username"/>
    <collection property="orders" ofType="Order">
        <id property="id" column="order_id"/>
        <result property="amount" column="amount"/>
        <result property="status" column="status"/>
    </collection>
</resultMap>

<select id="findUserWithOrders" resultMap="UserWithOrdersMap">
    SELECT u.id AS user_id, u.username,
           o.id AS order_id, o.amount, o.status
    FROM user u
    LEFT JOIN orders o ON u.id = o.user_id
    WHERE u.id = #{id}
</select>

案例是user属性有个部门对象,也就是1对1关系

ini 复制代码
<resultMap id="UserWithDeptMap" type="User">
    <id property="id" column="user_id"/>
    <result property="username" column="username"/>
    <association property="department" javaType="Department">
        <id property="id" column="dept_id"/>
        <result property="name" column="dept_name"/>
    </association>
</resultMap>

<select id="findUserWithDept" resultMap="UserWithDeptMap">
    SELECT u.id AS user_id, u.username,
           d.id AS dept_id, d.name AS dept_name
    FROM user u
    LEFT JOIN department d ON u.dept_id = d.id
    WHERE u.id = #{id}
</select>
相关推荐
咖啡八杯2 小时前
GoF设计模式——模板方法模式
java·后端·spring·设计模式
码事漫谈2 小时前
Loop 正在排斥人为操作
后端
爱勇宝3 小时前
办公资料反复修改、补传、交接混乱,我做了个桌面工具来解决这件事
前端·后端·程序员
庄周de蝴蝶3 小时前
梅开二度,这次拿下系统分析师
后端·程序员
林小帅4 小时前
NestJS v11 + Prisma v7 ESM 迁移配置解析
前端·javascript·后端
IT_陈寒5 小时前
React的setState竟然不是立刻生效的,害我调试半天
前端·人工智能·后端
逝水无殇6 小时前
C# 字符串(String)详解
开发语言·后端·c#
神奇小汤圆7 小时前
牛客网Java八股文|2026秋招面试题汇总(金九银十冲刺专用)
后端
cfm_29147 小时前
SpringBoot MockMvc
spring boot·后端·log4j