本文目录导读:

在Java中实现一对一查询(One-to-One Relationship)通常有两种常见方式:ORM框架(如MyBatis或JPA/Hibernate) 或 纯JDBC手动关联,下面分别给出案例。
使用 MyBatis 实现一对一查询
假设有两张表:user(用户)和 id_card(身份证),每个用户对应一张身份证。
数据库表结构
CREATE TABLE user (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50)
);
CREATE TABLE id_card (
id INT PRIMARY KEY AUTO_INCREMENT,
card_number VARCHAR(18) UNIQUE,
user_id INT UNIQUE, -- 一对一关键:唯一约束
FOREIGN KEY (user_id) REFERENCES user(id)
);
Java实体类
public class User {
private int id;
private String name;
private IdCard idCard; // 一对一关联
// getter/setter
}
public class IdCard {
private int id;
private String cardNumber;
private int userId;
// getter/setter
}
MyBatis Mapper(XML方式)
UserMapper.xml
<mapper namespace="com.example.mapper.UserMapper">
<!-- 方式1:嵌套结果(推荐,性能较好) -->
<select id="getUserWithIdCard" resultMap="userWithCardMap">
SELECT
u.id, u.name,
c.id as card_id, c.card_number, c.user_id
FROM user u
LEFT JOIN id_card c ON u.id = c.user_id
WHERE u.id = #{id}
</select>
<resultMap id="userWithCardMap" type="User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<!-- 一对一关联:使用 association -->
<association property="idCard" javaType="IdCard">
<id property="id" column="card_id"/>
<result property="cardNumber" column="card_number"/>
<result property="userId" column="user_id"/>
</association>
</resultMap>
<!-- 方式2:嵌套查询(N+1问题风险,谨慎使用) -->
<select id="getUserWithIdCardByNested" resultMap="userWithCardNestedMap">
SELECT * FROM user WHERE id = #{id}
</select>
<resultMap id="userWithCardNestedMap" type="User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<association property="idCard" column="id"
select="com.example.mapper.IdCardMapper.findById"/>
</resultMap>
</mapper>
调用示例
User user = userMapper.getUserWithIdCard(1); System.out.println(user.getName() + " - " + user.getIdCard().getCardNumber());
使用 JPA/Hibernate 实现一对一查询
实体类注解
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
@OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
private IdCard idCard;
// getter/setter
}
@Entity
@Table(name = "id_card")
public class IdCard {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "card_number")
private String cardNumber;
@OneToOne
@JoinColumn(name = "user_id", unique = true)
private User user;
// getter/setter
}
Repository查询
@Repository
public interface UserRepository extends JpaRepository<User, Integer> {
// 自动支持延迟加载,可直接调用
}
// 使用
User user = userRepository.findById(1).orElse(null);
System.out.println(user.getIdCard().getCardNumber()); // 自动加载身份证
纯 JDBC 手动实现(适合简单场景)
public User getUserWithIdCard(int userId) {
String sql = "SELECT u.*, c.* FROM user u LEFT JOIN id_card c ON u.id = c.user_id WHERE u.id = ?";
User user = null;
try (Connection conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, userId);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
user = new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
IdCard card = new IdCard();
card.setId(rs.getInt("c.id"));
card.setCardNumber(rs.getString("card_number"));
card.setUserId(rs.getInt("user_id"));
user.setIdCard(card);
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return user;
}
三种方式对比
| 方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| MyBatis | 灵活控制SQL,性能可控 | 需要写XML映射 | 复杂查询、SQL优化敏感 |
| JPA/Hibernate | 开发快,自动维护关联 | 学习曲线略高,延迟加载可能N+1 | 标准CRUD、快速开发 |
| 纯JDBC | 无框架依赖 | 代码重复多,难维护 | 极简单需求或框架限制 |
注意事项
- 数据库层面:一对一的本质是
外键 + 唯一约束(或主键即外键) - 性能考虑:
- MyBatis嵌套结果(JOIN一次)优于嵌套查询(多次查询)
- JPA建议使用
@EntityGraph或JOIN FETCH避免N+1
- 双向关联:避免JSON序列化循环,使用
@JsonIgnore或DTO
选择哪种方式取决于项目的技术栈和具体需求,大多数Java项目会用 MyBatis 或 JPA,很少再用纯JDBC。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播