Mybatis学习小结
Posted kklb
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis学习小结相关的知识,希望对你有一定的参考价值。
一、Mybatis简介
MyBatis的前身叫iBatis,本是apache的一个开源项目, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis。MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plan Old Java Objects,普通的Java对象)映射成数据库中的记录。
二、一个简单的demo
接下来介绍一个简单的例子,包含了Mybatis运行的基本过程
1. 导入相关的jar包
2. 创建相应的实体类bean,Users
package com.zhiyou100.klb.bean; public class Users private int id; private String name; private int age; public int getId() return id; public void setId(int id) this.id = id; public String getName() return name; public void setName(String name) this.name = name; public int getAge() return age; public void setAge(int age) this.age = age; public Users() super(); public Users(String name, int age) super(); this.name = name; this.age = age; public Users(int id, String name, int age) super(); this.id = id; this.name = name; this.age = age; @Override public String toString() return "Users [id=" + id + ", name=" + name + ", age=" + age + "]";
3. 创建mybatis的配置文件conf.xml
<?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> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mybatis" /> <property name="username" value="root" /> <property name="password" value="root" /> </dataSource> </environment> </environments> <mappers> <mapper resource="com/zhiyou100/klb/mapper/UsersMapper.xml"/> </mappers> </configuration>
4. 创建mybatis的映射文件,UsersMapper
<?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"> <!-- namespace:表示名称空间。现在的目的是区分id的. --> <mapper namespace="com.zhiyou100.klb.mapper.UsersMapper"> <!-- 根据id查询用户。id:标识该标签。 parameterType:参数类型。可以写 也可以省略 resultType:返回结果的类型。 #id:类似于EL表达式。 解析id的值 --> <select id="login" parameterType="map" resultType="Users"> <![CDATA[select * from users where age between #min and #max]]> </select> <select id="getUser" parameterType="int" resultType="Users"> select * from users where id = #id </select> <select id="getAll" resultType="Users"> select * from users </select> <insert id="add" parameterType="Users"> insert into users(name,age) values(#name,#age) </insert> <delete id="delete" parameterType="int"> delete from users where id = #id </delete> <update id="update" parameterType="Users"> update users set name = #name, age = #age where id = #id </update> </mapper>
5. mybatis的映射文件要引入到配置文件中,在第3步已引入
6. 建立Junit文件进行测试
package com.zhiyou100.klb.test; import java.io.Reader; import java.util.HashMap; import java.util.List; import java.util.Map; 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.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import com.zhiyou100.klb.bean.Users; class TestMybatis static SqlSession session = null; final String str = "com.zhiyou100.klb.mapper.UsersMapper"; @BeforeAll static void setUpBeforeClass() throws Exception //解析conf.xml Reader reader = Resources.getResourceAsReader("conf.xml"); //获取sessionFactory对象 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader); //获取session对象,用于操作数据库 session = sessionFactory.openSession(); @AfterAll static void tearDownAfterClass() throws Exception session.commit(); @Test void selectById() Users user = session.selectOne(str + ".getUser", 2); System.out.println(user); @Test void selectAll() List<Users> list = session.selectList(str + ".getAll"); System.out.println(list); @Test void login() Map<String, Integer> map = new HashMap<String, Integer>(); map.put("min", 10); map.put("max", 24); List<Users> list = session.selectList(str + ".login", map); System.out.println(list); @Test void add() Users user = new Users("刘老六", 25); int row = session.insert(str + ".add", user); System.out.println(row); @Test void delete() int row = session.delete(str + ".delete", 1); System.out.println(row); @Test void update() Users user = new Users(3,"王狗蛋",23); int row = session.update(str + ".update", user); System.out.println(row);
三、优化Mybatis
1.如果映射文件中的查询条件有多个,则可以使用Map集合作为参数
@Test void login() Map<String, Integer> map = new HashMap<String, Integer>(); map.put("min", 10); map.put("max", 24); List<Users> list = session.selectList(str + ".login", map); System.out.println(list);
2.将属性文件单独列出db.properties,需要将属性文件导入Mybatis配置文件中,之后使用$
#数据源信息 jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mybatis jdbc.username=root jdbc.password=123456
<?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> <!--引入属性文件 --> <properties resource="db.properties"></properties> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="$jdbc.driver" /> <property name="url" value="$jdbc.url" /> <property name="username" value="$jdbc.username" /> <property name="password" value="$jdbc.password" /> </dataSource> </environment> </environments> <mappers> <mapper resource="com/zhiyou100/klb/mapper/UsersMapper.xml"/> </mappers> </configuration>
3.为实体类起别名,为包下所有类起别名,别名为类名(不建议使用,不方便别人解读代码)
<!-- 为包下的所有实体类起别名,别名为类名 --> <typeAliases> <package name="com.zhiyou100.klb.bean"/> </typeAliases>
4.导入log4j-1.2.17.jar包后加入日志信息log4j.properties,方便查错以及查看运行过程
log4j.properties, log4j.rootLogger=DEBUG, Console #Console log4j.appender.Console=org.apache.log4j.ConsoleAppender log4j.appender.Console.layout=org.apache.log4j.PatternLayout log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n log4j.logger.java.sql.ResultSet=INFO log4j.logger.org.apache=INFO log4j.logger.java.sql.Connection=DEBUG log4j.logger.java.sql.Statement=DEBUG log4j.logger.java.sql.PreparedStatement=DEBUG
四、接口与映射文件结合使用
1.创建一个接口,该接口要和映射文件匹配。方法名=ID名
package com.zhiyou100.klb.dao; import java.util.List; import org.apache.ibatis.annotations.Param; import com.zhiyou100.klb.bean.Users; public interface UsersDao /** * 根据id查询 * @param id */ public Users getUser(int id); /** * age在min和max之间 * @param min * @param max * @return */ public List<Users> login(@Param("min") int min, @Param("max") int max); /** * 查询所有 * @return */ public List<Users> getAll(); /** * 添加 * @param user */ public void add(Users user); /** * 根据ID删除 * @param id */ public void delete(int id); /** * 更新 * @param user */ public void update(Users user);
2.映射文件中,命名空间要与映射文件路径一直,例如:com.zhiyou100.klb.dao.UsersDao
<?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"> <!-- namespace:表示名称空间。现在的目的是区分id的. --> <mapper namespace="com.zhiyou100.klb.dao.UsersDao"> <!-- 根据id查询用户。id:标识该标签。 parameterType:参数类型。可以写 也可以省略 resultType:返回结果的类型。 #id:类似于EL表达式。 解析id的值 --> <select id="login" parameterType="map" resultType="Users"> <![CDATA[select * from users where age >= #min and age <= #max]]> </select> <select id="getUser" parameterType="int" resultType="Users"> select * from users where id = #id </select> <select id="getAll" resultType="Users"> select * from users </select> <insert id="add" parameterType="Users" useGeneratedKeys="true" keyProperty="id"> insert into users(name,age) values(#name,#age) </insert> <delete id="delete" parameterType="int"> delete from users where id = #id </delete> <update id="update" parameterType="Users"> update users set name = #name, age = #age where id = #id </update> </mapper>
3.建立Junit文件测试程序运行状况,
package com.zhiyou100.klb.test; import java.io.Reader; import java.util.List; 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.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import com.zhiyou100.klb.bean.Users; import com.zhiyou100.klb.dao.UsersDao; class TestUsers static SqlSession session = null; static UsersDao usersDao; @BeforeAll static void setUpBeforeClass() throws Exception //解析conf.xml Reader reader = Resources.getResourceAsReader("conf.xml"); //获取sessionFactory对象 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader); //获取session对象,用于操作数据库 session = sessionFactory.openSession(); //得到接口的实现类 usersDao = session.getMapper(UsersDao.class); @AfterAll static void tearDownAfterClass() throws Exception session.commit(); @Test void selectById() System.out.println(usersDao.getUser(2)); @Test void login() List<Users> list = usersDao.login(10, 24); System.out.println(list); @Test void add() usersDao.add(new Users("刘老头", 65)); @Test void delete() usersDao.delete(5); @Test void update() usersDao.update(new Users(3,"王二傻",22));
五、解决列名与属性名不一致的情况
1.在SQL语句中为字段起别名,别名与类的属性名一致
<!-- 起别名 --> <select id="getTeacher" resultType="com.zhiyou100.klb.bean.Teacher"> select t_id tid,t_name tname from teacher where t_id = #id </select>
2.利用resultMap
<!--引用resultMap标签 --> <select id="getOrder" parameterType="int" resultMap="ordersMap"> select * from orders where order_id = #id </select> <!--resultMap:写数学与字段的对应关系 type:表示哪个实体类与表的对应关系 --> <resultMap type="com.zhiyou100.klb.bean.Orders" id="ordersMap"> <!-- ID:表示表中的主键与实体类的属性的对应关系 --> <id column="order_id" property="id"/> <result column="order_no" property="no"/> <result column="order_price" property="price"/> </resultMap>
六、关联查询
1.多对一或一对一,如一个班级一个老师,利用association标签
<!--引用resultMap标签 --> <select id="getClazz" parameterType="int" resultMap="clazzMap"> select * from class c,teacher t where c.teacher_id=t.t_id and c_id = #id </select> <!--resultMap:写数学与字段的对应关系 type:表示哪个实体类与表的对应关系 --> <resultMap type="com.zhiyou100.klb.bean.Clazz" id="clazzMap"> <!-- ID:表示表中的主键与实体类的属性的对应关系 --> <id column="c_id" property="cid"/> <result column="c_name" property="cname"/> <result column="teacher_id" property="tid"/> <!-- 该类中引入的一的一方的属性
property:属性名
javaType:该属性的java类型
--> <association property="teacher" javaType="com.zhiyou100.klb.bean.Teacher"> <id column="t_id" property="tid"/> <result column="t_name" property="tname"/> </association> </resultMap>
2.一对多,如一个班级多个学生,利用collection标签
<!--引用resultMap标签 --> <select id="getClazz" parameterType="int" resultMap="clazzMap"> select * from class c,teacher t,student s where c.teacher_id=t.t_id and c.c_id=s.class_id and c.c_id = #id </select> <!--resultMap:写数学与字段的对应关系 type:表示哪个实体类与表的对应关系 --> <resultMap type="com.zhiyou100.klb.bean.Clazz" id="clazzMap"> <!-- ID:表示表中的主键与实体类的属性的对应关系 --> <id column="c_id" property="cid"/> <result column="c_name" property="cname"/> <result column="teacher_id" property="tid"/> <association property="teacher" javaType="com.zhiyou100.klb.bean.Teacher"> <id column="t_id" property="tid"/> <result column="t_name" property="tname"/> </association> <!-- ofType:集合中泛型的类型 --> <collection property="students" ofType="com.zhiyou100.klb.bean.Student"> <id column="s_id" property="sid"/> <result column="s_name" property="sname"/> <result column="class_id" property="cid"/> </collection> </resultMap>
七、动态sql语句
1、动态SQL:if 语句
<select id="selectUserByUsernameAndSex" resultType="user" parameterType="com.ys.po.User">
select * from user where
<if test="username != null">
username=#username
</if>
<if test="username != null">
and sex=#sex
</if>
</select>
2、动态SQL:if+where 语句
<select id="selectUserByUsernameAndSex" resultType="user" parameterType="com.ys.po.User">
select * from user
<where>
<if test="username != null">
username=#username
</if>
<if test="username != null">
and sex=#sex
</if>
</where>
</select>
3、动态SQL:if+set 语句
<!-- 根据 id 更新 user 表的数据 -->
<update id="updateUserById" parameterType="com.ys.po.User">
update user u
<set>
<if test="username != null and username != ‘‘">
u.username = #username,
</if>
<if test="sex != null and sex != ‘‘">
u.sex = #sex
</if>
</set>
where id=#id
</update>
4、动态SQL:choose(when,otherwise) 语句
<select id="selectUserByChoose" resultType="com.ys.po.User" parameterType="com.ys.po.User">
select * from user
<where>
<choose>
<when test="id !=‘‘ and id != null">
id=#id
</when>
<when test="username !=‘‘ and username != null">
and username=#username
</when>
<otherwise>
and sex=#sex
</otherwise>
</choose>
</where>
</select>
5、动态SQL:trim 语句
<select id="selectUserByUsernameAndSex" resultType="user" parameterType="com.ys.po.User">
select * from user
<!-- <where>
<if test="username != null">
username=#username
</if>
<if test="username != null">
and sex=#sex
</if>
</where> -->
<trim prefix="where" prefixOverrides="and | or">
<if test="username != null">
and username=#username
</if>
<if test="sex != null">
and sex=#sex
</if>
</trim>
</select>
6、动态SQL: SQL 片段
<!-- 定义sql片段 -->
<sql id="usersColum">id,name,age,sex</sql>
<select id="getUser" parameterType="int" resultType="Users">
select
<!-- 引用sql片段 -->
<include refid="usersColum"></include>
from users where id = #id
</select>
7、动态SQL: foreach 语句
<delete id="delete">
delete from users
<where>
<!--
collection:指定输入对象中的集合属性
item:每次遍历生成的对象
open:开始遍历时的拼接字符串
close:结束时拼接的字符串
separator:遍历对象之间需要拼接的字符串
select * from user where
1
=
1
and id in (
1
,
2
,
3
)
-->
<foreach collection="ids" open=" id in (" close=")" separator="," item="id">
#id
</foreach>
</where>
</delete>
8.动态sql与模糊查询
<select id="getUser" parameterType="int" resultType="Users">
select
<!-- 引用sql片段 -->
<include refid="usersColum"></include>
from users where id like concat(‘%‘,#id,‘%‘)
</select>
八、逆向工程(generator)
通过前面的学习,在实际开发中,我们基本上能对mybatis应用自如了,但是我们发现了一个问题,所有操作都是围绕着po类,xxxMapper.xml文件,xxxMapper接口等文件来进行的。如果实际开发中数据库的表特别多,那么我们需要手动去写每一张表的po类,xxxMapper.xml,xxxMapper.java文件,这显然需要花费巨大的精力,而且可能由于表字段太多,写错了而不知道也是可能的。
所以我们在实际开发中,一般使用逆向工程方式来自动生成所需的文件。
1.新建一个工程并导入相应的jar包
2.创建配置文件generator.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- mysql驱动jar所在的位置 -->
<classPathEntry location="E:\\\\NJDF\\\\mysql-connector-java-5.1.47.jar\\\\" />
<!-- 数据源的信息 -->
<context id="DB2Tables" targetRuntime="MyBatis3">
<!-- 禁止所有注释 -->
<commentGenerator>
<property name="suppressAllComments" value="true" />
</commentGenerator>
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis"
userId="root"
password="123456">
</jdbcConnection>
<javaTypeResolver >
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- 生产的实体类所在的位置 -->
<javaModelGenerator targetPackage="com.zhiyou100.klb.bean" targetProject="./src">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- 生成的映射文件所在的位置 -->
<sqlMapGenerator targetPackage="com.zhiyou100.klb.mapper" targetProject="./src">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!-- 生产的dao文件所在的位置 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.zhiyou100.klb.dao" targetProject="./src">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!-- 某张表与实体类的对象关系
schema:该表所在的数据库
tableName:表名
domainOb:实体类名
-->
<table schema="mybatis" tableName="users" domainObjectName="Users" enableCountByExample="false"
enableDeleteByExample="false" enableSelectByExample="false" enableUpdateByExample="false">
<property name="useActualColumnNames" value="true"/>
<generatedKey column="ID" sqlStatement="DB2" identity="true" />
<columnOverride column="DATE_FIELD" property="startDate" />
<ignoreColumn column="FRED" />
<columnOverride column="LONG_VARCHAR_FIELD" jdbcType="VARCHAR" />
</table>
</context>
</generatorConfiguration>
3.运行主程序生成代码
package com.zhiyou100.klb.test;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
public class Test
public static void main(String[] args) throws Exception
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("generator.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
九、分页助手(pagehelper)
1.引入jar包
2.在MyBatis配置xml中配置拦截器插件
<!-- plugins在配置文件中的位置必须符合要求,否则会报错,顺序如下: properties?, settings?, typeAliases?, typeHandlers?, objectFactory?,objectWrapperFactory?, plugins?, environments?, databaseIdProvider?, mappers? --> <plugins> <!-- com.github.pagehelper为PageHelper类所在包名 --> <plugin interceptor="com.github.pagehelper.PageInterceptor"> <!-- 使用下面的方式配置参数,后面会有所有的参数介绍 --> <property name="param1" value="value1"/> </plugin> </plugins>
3.如何在代码中使用,使用pageInfo的用法
package com.zhiyou100.klb.test; import java.io.Reader; import java.util.List; 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.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.zhiyou100.klb.bean.Users; import com.zhiyou100.klb.dao.UsersMapper; class TestUsers static SqlSession session = null; static UsersMapper usersMapper; @BeforeAll static void setUpBeforeClass() throws Exception //解析conf.xml Reader reader = Resources.getResourceAsReader("conf.xml"); //获取sessionFactory对象 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader); //获取session对象,用于操作数据库 session = sessionFactory.openSession(); //得到接口的实现类 usersMapper = session.getMapper(UsersMapper.class); @AfterAll static void tearDownAfterClass() throws Exception session.commit(); @Test void selectAll() //设置分页 当前页码和每页显示的记录数 int pageNum = 1; int pageSize = 5; PageHelper.startPage(pageNum, pageSize); //执行sql功能 List<Users> list = usersMapper.selectAll(); //用PageInfo对结果进行包装 PageInfo<Users> page = new PageInfo<Users>(list,10); System.out.println("总页码:" + page.getPages()); System.out.println("当前页:" + page.getPageNum()); System.out.println("上一页:" + page.getPrePage()); int[] pages = page.getNavigatepageNums(); for (int i : pages) System.out.print(i + "\\t"); System.out.println("下一页:" + page.getNextPage()); List<Users> a = page.getList(); for (Users u : a) System.out.println(u);
十、$和#的区别
#
使用#意味着使用的预编译的语句,即在使用jdbc时的preparedStatement,sql语句中如果存在参数则会使用?作占位符,我们知道这种方式可以防止sql注入,并且在使用#时形成的sql语句,已经带有引号,例,select * from table1 where id=#id 在调用这个语句时我们可以通过后台看到打印出的sql为:select * from table1 where id=‘2‘ 加入传的值为2.也就是说在组成sql语句的时候把参数默认为字符串。
$
使用$时的sql不会当做字符串处理,是什么就是什么,如上边的语句:select * from table1 where id=$id 在调用这个语句时控制台打印的为:select * from table1 where id=2 ,假设传的参数值为2
从上边的介绍可以看出这两种方式的区别,我们最好是能用#则用它,因为它可以防止sql注入,且是预编译的,在需要原样输出时才使用$,如,
select * from $tableName order by $id 这里需要传入表名和按照哪个列进行排序 ,加入传入table1、id 则语句为:select * from table1 order by id
如果是使用# 则变成了select * from ‘table1‘ order by ‘id‘ 我们知道这样就不对了。
十一、添加时如何获取添加成功后的主键值
Mybatis 配置文件 useGeneratedKeys 参数只针对 insert 语句生效,默认为 false。当设置为 true 时,表示如果插入的表以自增列为主键,则允许 JDBC 支持自动生成主键,并可将自动生成的主键返回。keyProperty是与主键对应的Java对象的属性名。
<insert id="add" parameterType="Users" useGeneratedKeys="true" keyProperty="id"> insert into users(name,age) values(#name,#age) </insert>
以上是关于Mybatis学习小结的主要内容,如果未能解决你的问题,请参考以下文章