工作原理
- 首先,开发人员通过XML或注解配置文件来描述Java对象和SQL语句之间的映射关系。
- 当Java程序需要访问数据库时,MyBatis会根据配置文件自动生成SQL语句,并将Java对象转换为数据库中的数据类型。
- MyBatis使用JDBC API来执行SQL语句,并将查询结果映射回Java对象中。
- 最后,Java程序可以通过MyBatis提供的API来访问数据库,并对数据进行增删改查等操作。
MyBatis的使用
- 添加依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency
- 相关配置文件 主配置文件(在resources资源文件夹下)
<configuration>
<!--设置数据库连接的信息-->
<properties resource="db.properties"/>
<!--给实体类别名-->
<typeAliases>
<package name="com.woniu.mybatis.entity"/>
</typeAliases>
<!--环境-->
<environments default="development">
<environment id="development">
<!--事务处理器-->
<transactionManager type="JDBC"></transactionManager>
<!--数据源类型POOLED池-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!--配置mapper映射文件的位置-->
<mappers>
<!--当要映射单个mapper映射文件-->
<!--<mapper resource="com/...../xml文件名"></mapper>-->
<!--映射整个mapper包下的接口-->
<package name="包名.mapper"/>
</mappers>
</configuration>
-
映射文件Mapper.xml
这个xml文件必须和每一个mapper接口映射,xml文件里面写的是mapper接口的sql实现
<mapper namespace="对应mapper接口的完整名称">
<select id="接口方法名" resultType="返回结果类型" parameterType="复杂类型(这个用于包装类型)">
sql语句
</select>
<!--假设在这个例子中,`selectUserById`是这个select标签的唯一标识,`com.example.User`是返回结果的类型(这里假设返回的结果是一个名为User的Java对象),`com.example.User`是传入参数的类型(这里假设传入的参数是一个名为User的对象,包含id和name两个属性)。当调用`selectUserById`方法时,MyBatis会执行对应的SQL语句,并将结果封装成User对象返回。在这个例子中,SQL语句中还包含了对name属性的判断,确保只有当传入的User对象的name属性不为空时,才会根据id查询用户信息。-->
<select id="selectUserById" resultType="com.example.User" parameterType="com.example.User">
SELECT * FROM user WHERE id = #{id} AND name = #{name}
</select>
</mapper>
- 添加resultMap为结果集赋值
<resultMap id="houseResultMap" type="House">
<!--主键列用id,其他列用result-->
<id column="id" property="id"/>
<result column="numbers" property="numbers"/>
<!--对于复杂类型,使用关联配置association-->
<association property="building" javaType="Building">
<id column="bid" property="id"/>
<result column="bnumbers" property="numbers"/>
</association>
</resultMap>
<select id="selectAllHouses" resultMap="houseResultMap">
sql语句(用到关联查询)
</select>
- 案例 接口中的方法
int insertUser(User user);
映射文件(#{}中的属性值和实体类的属性一一对应)
<insert id="insertUser" parameterType="com.example.User" keyProperty="id" keyColumn="id">
INSERT INTO user (name, age) VALUES (#{name}, #{age})
</insert>
- 日志信息查看sql语句 首先导入依赖
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
然后加入log4j.properties
#避免了自己常见Logger日志对象
#console表示在控制台输出
log4j.rootLogger=debug,console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%p %c %d{yyyy-MM-dd HH:mm:ss} %m%n
- 多参数查询 常用的方法是 添加@Param注解,添加了注解之后才能被识别
List<House> queryHouses(@Param("buildingId") int buildingId, @Param("area") double area);
- 动态查询 最主要的是if、choose、when、otherwise、trim、where以及set标签
<!--if标签的使用-->
<select id="findUserByCondition" resultType="User">
select * from user
<where>
<if test="username != null">
and username like '%${username}%'
</if>
<if test="age != null">
and age = #{age}
</if>
</where>
</select>
<!--choose、when、otherwise标签的使用-->
<!--在这个例子中,我们使用了标签来根据不同的条件执行不同的SQL语句块。当传入的参数中name属性不为空时,会执行第一个SQL语句块;否则,会执行第二个SQL语句块-->
<select id="selectUserById" resultType="com.example.User">
SELECT * FROM user WHERE id = #{id}
<choose>
<when test="name != null and name != ''">
AND name = #{name}
</when>
<otherwise>
AND age = #{age}
</otherwise>
</choose>
</select>
<!--trim标签的使用-->
<select id="selectUserByAge" resultType="com.example.User">
SELECT * FROM user
<!--这里为什么要使用prefixOverrides呢?我的理解是where后面不能拼接and,但是呢,加入prefixOverrides的话可以自动去掉and,这样sql语句就可以正常拼接了-->
<trim prefix="WHERE" prefixOverrides="AND |OR ">
<if test="id != null">
AND id = #{id}
</if>
<if test="name != null and name != ''">
AND name = #{name}
</if>
<if test="age != null">
AND age >= #{age}
</if>
</trim>
</select>
<!--在这个例子中,我们使用了set标签来根据条件对查询结果进行排序。在标签中,我们使用元素来指定排序条件。在元素中,我们使用test属性来指定条件表达式,以判断是否应该执行该SQL片段-->
<select id="selectUserByAge" resultType="com.example.User">
SELECT * FROM user
<set>
<if test="id != null">
ORDER BY id ASC
</if>
<if test="name != null and name != ''">
ORDER BY name ASC
</if>
<if test="age != null">
ORDER BY age ASC
</if>
</set>
</select>
分页查询
- 第一种方式 使用RowBounds(MyBatis自带的一个简单分页功能)方式
//接口
List<User> getUsersByPage(RowBounds rowBounds);
<!--映射文件-->
<select id="getUsersByPage" resultType="User">
select * from user limit #{offset}, #{limit}
</select>
//service层调用mapper层
javaCopy codeint offset = 0;
int limit = 10;
RowBounds rowBounds = new RowBounds(offset, limit);
List<User> users = userMapper.getUsersByPage(rowBounds);
- 第二种方式 使用PageHelper插件 优点:可以实现物理分页和逻辑分页,同时还支持多种数据库方言(数据库方言是指不同数据库系统在 SQL 语法、数据类型、函数和存储过程等方面存在的差异。引入数据库方言的目的是为了实现对查询的优化,实现分页语句以及count语句的自动生成,方言会生成适合于该特定数据库的效率较高的SQL语法)
<!--首先导入依赖-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
<!--在配置文件中配置PageHeler插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!--配置datebase方言,表示我们要为哪种数据库添加分页支持,每种数据库的分页指令不同-->
<property name="helperDialect" value="mysql"/>
<!--配置合理化查询,作用:当页码超出范围时,返回最后一页的数据-->
<property name="reasonable" value="true"/>
</plugin>
</plugins>
//接口
List<User> getUsersByPage();
<!--映射文件-->
<select id="getUsersByPage" resultType="User">
select * from user
</select>
int pageNum = 1;
int pageSize = 10;
//开启分页操作
PageHelper.startPage(pageNum, pageSize);
//下面一行返回一个Page对象,包含了查询结果以及分页相关的信息,如当前页码、每页显示的数据条数、总记录数等
List<User> list = userMapper.selectUsers();
//PageInfo<User> 是通过 Page 对象生成的分页信息对象
PageInfo<User> pageInfo = new PageInfo<>(list);
List<User> users = userMapper.getUsersByPage(page);