目录
❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️
❤️❤️❤️
家人们,今天我可得跟你们唠唠我在 Java 编程学习里发现的一个超厉害的 “神器”——MyBatis。你们知道咱们写 Java 程序的时候,经常得跟数据库打交道,存数据、取数据,要是没有个趁手的工具,那可太费劲了。以前用传统的 JDBC 操作,写起代码来又长又啰嗦,还特别容易出错。这时候 MyBatis 就闪亮登场啦,它就像是咱们和数据库之间的一个超智能 “翻译官”,能把咱们 Java 代码里的操作指令,巧妙又高效地翻译成数据库能懂的语言,大大简化了数据库交互的流程,让咱们开发程序的效率蹭蹭往上涨,所以说,学好 MyBatis 对提升咱们的编程技能那可是相当重要!
❤️❤️❤️
❤️二、开发环境搭建指南
💛(一)工具和依赖准备
首先啊,咱们得把基础的工具准备好。JDK 那肯定是必不可少的啦,就好比咱们做饭得有锅,得安装一个合适的版本,建议至少是 JDK 8 及以上,这样才能保证后续运行顺畅。再就是 IDE,我推荐 IntelliJ IDEA,它就像是一个超豪华的编程厨房,各种功能一应俱全,用起来特别顺手。安装的时候,跟着安装向导一步一步来就行,没啥复杂的。
💛💛💛💛
有了工具,还得引入依赖。要是咱们用 Maven 来管理项目(就像找了个超细心的管家帮咱们打理项目需要的各种资源),就在项目的 pom.xml 文件里加上下面这些代码:
❤️❤️❤️❤️
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.10</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.28</version> </dependency>
这里的版本号你们可以去官网看看,有没有更新的,用最新的一般没啥问题。要是用 Gradle 管理项目,也类似,在 build.gradle 文件里这么写:
implementation 'org.mybatis:mybatis:3.5.10' implementation 'mysql:mysql-connector-java:8.0.28'
这就相当于告诉项目:“嘿,我要用 MyBatis 和 MySQL 数据库啦,你得把它们准备好。” 引入完依赖,咱们就迈出了成功的第一步。
❤️(二)配置文件设置
- 接下来讲讲 MyBatis 的核心配置文件,一般叫 mybatis-config.xml,这可是整个 MyBatis 运行的 “大脑中枢”。里面有几个关键要素,比如说数据源配置,这就像是告诉 MyBatis 数据库住在哪儿,用户名和密码是啥,才能连得上。要是连接 MySQL 数据库,代码大概是这样:💚💚💚💚💚
<dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource>
注意啊,这里的 url 里的参数设置很重要,不同数据库驱动可能有不同要求,像 MySQL 8.0 就得加上时区设置,不然可能连不上或者报错。再就是环境切换,如果咱们开发、测试、生产环境用不同的数据库,就可以在配置文件里设置不同的环境,方便切换,就像换不同的衣服应对不同场合。还有别名设置,给一些常用的 Java 类在 MyBatis 里取个别名,后面写 SQL 映射的时候就方便多了,比如:
<typeAliases> <typeAlias alias="User" type="com.example.User"/> </typeAliases>
这就给咱们的 User 类取了个简单的别名 “User”,是不是很实用?
- 再说说 SQL 映射文件,这玩意也特别重要,它就像是 MyBatis 的 “翻译手册”,把咱们写的 Java 方法和 SQL 语句对应起来。一般起名有个规则,比如咱们有个 UserMapper 接口,对应的 SQL 映射文件就叫 UserMapper.xml,得放在合适的目录下,让 MyBatis 能找到,通常放在 resources 目录下的 mapper 文件夹里。然后要在核心配置文件里把它关联起来,像这样:
<mappers> <mapper resource="mapper/UserMapper.xml"/> </mappers>
在 SQL 映射文件里,咱们就可以写各种 SQL 语句啦,像查询用户信息:
<select id="getUserById" resultType="User"> select * from users where id = #{id} </select>
这里的 id 就是对应 Java 方法的名字,resultType 是返回结果的类型,也就是咱们之前取别名的 User 类,这样 MyBatis 就能准确地把查询结果封装成咱们想要的 User 对象啦,是不是特别巧妙?
💜三、基础操作实例详解
❤️(一)表与实体类创建
咱们来实际操作一下,以一个简单的 “用户信息表” 为例,建表的 SQL 语句大概是这样:
CREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL, password VARCHAR(50) NOT NULL, email VARCHAR(100) );
这表有几个字段,ID 是主键,自动增长,用户名和密码不能为空,还有个邮箱字段。对应咱们得创建一个 Java 实体类,就叫 User:
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; public class User { private Integer id; private String username; private String password; private String email; }
这里我用了 Lombok 来简化代码,自动帮咱们生成 get、set、toString 等方法,这样代码看起来简洁多了。实体类的属性和表字段是一一对应的,这样 MyBatis 在做数据传输的时候,就能很方便地把表中的数据封装成 User 对象,或者把 User 对象的数据存到表里面,是不是很好理解?
❤️(二)CRUD 操作全流程
- 查询:在 Mapper.xml 中写查询语句,比如咱们要根据 ID 查询单个用户,代码刚才给大家看过了,再详细讲讲。<select>标签里的 id 必须和对应的 Mapper 接口里的方法名一样,resultType 就是咱们要返回的实体类类型,这里是 User。在 Java 代码里,咱们得先获取一个 SqlSession,这就像是打开了和数据库沟通的大门:
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession();
这里的 inputStream 是读取核心配置文件得到的,先别管它怎么来的,重点是拿到 SqlSession 后,咱们就能调用 Mapper 方法了:
UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = userMapper.getUserById(1); System.out.println(user);
这里通过 getMapper 方法拿到 UserMapper 的代理对象,然后调用 getUserById 方法,传入要查询的用户 ID,就能拿到对应的 User 对象,最后打印出来看看是不是咱们想要的结果。要是查询所有用户,SQL 语句改改就行:
<select id="getAllUsers" resultType="User"> select * from users </select>
Java 代码里调用 getAllUsers 方法就能拿到所有用户的列表啦,是不是挺简单的?
- 插入:插入新用户也不难,用<insert>标签,比如:
<insert id="addUser" useGeneratedKeys="true" keyProperty="id"> insert into users (username, password, email) values (#{username}, #{password}, #{email}) </insert>
这里的 useGeneratedKeys 和 keyProperty 很重要,它能让数据库自动生成主键,并且把主键值赋给实体类的 id 属性,这样咱们插入完数据后,就能直接拿到新生成的主键值啦。在 Java 代码里:
User newUser = new User(null, "张三", "123456", "zhangsan@example.com"); int rows = userMapper.addUser(newUser); sqlSession.commit(); if (rows > 0) { System.out.println("插入成功,新用户 ID:" + newUser.getId()); }
先创建一个新的 User 对象,调用 addUser 方法插入,然后提交事务,判断返回的行数,如果大于 0 就说明插入成功,还能拿到新用户的 ID,是不是很方便?
- 更新:更新用户信息用<update>标签,比如说咱们要更新用户的密码:❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️
<update id="updateUserPassword"> update users <set> password = #{password} </set> where id = #{id} </update>
这里用<set>标签很巧妙,它能避免在更新多个字段时出现多余的逗号,保证 SQL 语法正确。在 Java 代码里:
User updateUser = new User(1, null, "newpassword", null); int rows = userMapper.updateUserPassword(updateUser); sqlSession.commit(); if (rows > 0) { System.out.println("更新成功"); }
创建一个包含要更新字段的 User 对象,调用 updateUserPassword 方法,提交事务,判断返回行数确定是否更新成功。要是有多个字段要更新,就在<set>标签里多写几个就行,像这样:
<update id="updateUserInfo"> update users <set> username = #{username}, password = #{password}, email = #{email} </set> where id = #{id} </update>
在复杂的业务里,可能还涉及到事务控制,比如同时更新多个表的数据,就得保证要么全成功,要么全失败,这时候就得合理使用 MyBatis 的事务功能,后面再详细讲。
- 删除:删除用户就简单多了,用<delete>标签:
<delete id="deleteUserById"> delete from users where id = #{id} </delete>
在 Java 代码里:
int rows = userMapper.deleteUserById(1); sqlSession.commit(); if (rows > 0) { System.out.println("删除成功"); }
调用 deleteUserById 方法,传入要删除的用户 ID,提交事务,判断返回行数。不过要注意,如果表之间有外键约束,直接删除可能会报错,得先处理好外键关系,保护好数据的完整性,别把数据删乱了。
❤️四、进阶特性探索
💛(一)动态 SQL 魔法
- 有时候咱们查询用户,条件不是固定的,可能根据用户名、年龄等多个条件组合查询,这时候动态 SQL 就派上用场了。用<if>标签,比如:💚💚💚💚
<select id="getUsersByCondition" resultType="User"> select * from users <where> <if test="username!= null"> and username like '%${username}%' </if> <if test="age!= null"> and age = #{age} </if> </where> </select>
这里的<where>标签也很有用,它能自动帮咱们去掉多余的 and 或者 or,让 SQL 语法更正确。<if>标签里的 test 是条件判断,根据传入的参数决定要不要加这个查询条件。注意啊,这里用 ${} 和 #{} 有区别,#{} 能防止 SQL 注入,更安全,所以尽量用 #{},除非有特殊情况。这种动态 SQL 比咱们硬编码的 SQL 灵活多了,能满足各种复杂的查询需求。
- 要是条件更复杂,有优先级之分,就可以用<choose>、<when>、<otherwise>标签,比如:❤️❤️
<select id="getUserByPriority" resultType="User"> select * from users <where> <choose> <when test="id!= null"> and id = #{id} </when> <when test="username!= null"> and username like '%${username}%' </when> <otherwise> and age > 18 </otherwise> </choose> </where> </select>
这就像是一个多分支的选择结构,先看有没有 ID,如果有就按 ID 查,如果没有再看用户名,都没有就查年龄大于 18 的用户,这样代码简洁性大大提升,查询也更灵活。
- 还有个超厉害的<foreach>标签,在批量操作里用处很大。比如说批量插入用户列表:❤️❤️❤️❤️
<insert id="addUsersBatch"> insert into users (username, password, email) values <foreach collection="userList" item="user" separator=","> (#{user.username}, #{user.password}, #{user.email}) </foreach> </insert>
这里的 collection 是传入的集合参数名字,item 是集合里每个元素的别名,separator 是分隔符,这样就能一次性插入多条数据,比一条条插入快多了。批量删除也类似,把 SQL 语句改成 delete 就行,大家可以试试。对比单条插入,批量插入在性能上有巨大优势,特别是数据量大的时候,能节省好多时间,不过也要注意数据量太大可能会超出数据库的处理能力,得根据实际情况优化。
❤️(二)缓存机制揭秘
- MyBatis 有个很神奇的缓存机制,能提高查询性能。先说说一级缓存,它是在同一个 SqlSession 里起作用的。比如说咱们第一次查询一个用户:❤️❤️
SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user1 = userMapper.getUserById(1); System.out.println(user1);
这时候 MyBatis 会把查询结果放到一级缓存里,要是咱们紧接着再查询一次同一个用户:
User user2 = userMapper.getUserById(1); System.out.println(user2);
你会发现,这次查询并没有真正去数据库查,而是直接从缓存里拿的,因为缓存命中了,速度超快。但要注意,一旦咱们关闭了 SqlSession,缓存就没了,就像咱们关了冰箱门,里面的东西就拿不到了。而且如果在缓存期间,数据库里的数据被别人改了,咱们缓存里的数据就可能不一致了,这时候就得小心使用,别被过期数据误导了。
- 再讲讲二级缓存,它的范围更大,是在整个 MyBatis 配置的范围内。咱们得先在 MyBatis 配置文件里开启全局缓存:❤️❤️❤️❤️❤️❤️
<configuration> <settings> <setting name="cacheEnabled" value="true"/> </settings> </configuration>
然后在 Mapper.xml 文件里配置缓存标签:
<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️
这里的 eviction 是缓存淘汰策略,LRU 就是最近最少使用,flushInterval 是刷新间隔,size 是缓存大小,readOnly 是缓存是否只读,这些参数可以根据实际情况调整。不同命名空间的 Mapper 缓存是分开的,只有在同一个命名空间下的查询才会共享缓存。比如说咱们有个多表关联查询,涉及到用户表和订单表,在查询用户及其订单信息的时候,第一次查完,二级缓存会把结果存起来,下次再查,如果数据没变化,就能直接从缓存里拿,大大提升了性能。不过要是数据更新了,就得想办法更新缓存,不然又会出现数据不一致的问题,这也是个技术活,得好好琢磨。
❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️