MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。 MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
创建java项目,新建一个lib文件夹,导入依赖
mybatis-3.2.7.jar----mybatis的核心包
mysql-connector-java-5.1.37-bin.jar ---mysql驱动包
编写mybatis核心配置文件sqlMapConfig.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> <typeAliases> <!-- <typeAlias type="com.gh.entity.Login" alias="login"></typeAlias>--> <package name="com.gh.entity"/> </typeAliases> <properties resource="db.properties"/> <!--environments代表所有环境的集合,可以写多个,default指定默认使用哪个--> <environments default="mybatis"> <!--数据库配置--> <environment id="mybatis"> <!--事务管理JDBC:交给jdbc管理, MANAGED:被spring管理--> <transactionManager type="JDBC"></transactionManager> <!--type:是否使用连接池 POOLED:使用连接池 UNPOOLED:不使用连接池 JNDI:找服务去要连接 --> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <mappers> <mapper resource="login.xml"></mapper> <package name="com.gh.dao"></package> </mappers> </configuration>
编写数据库配置文件db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/dingchan?characterEncoding=utf-8
username=root
password=root
编写实体类Login.java
package com.gh.entity; /** * @Author Eric * @Date 2021/7/1 20:14 * @Version 1.0 */ public class Login { private Integer login_id; private String login_name; private String password; private String phone; public Integer getLogin_id() { return login_id; } public void setLogin_id(Integer login_id) { this.login_id = login_id; } public String getLogin_name() { return login_name; } public void setLogin_name(String login_name) { this.login_name = login_name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } @Override public String toString() { return "Login{" + "login_id=" + login_id + ", login_name=‘" + login_name + ‘\‘‘ + ", password=‘" + password + ‘\‘‘ + ", phone=‘" + phone + ‘\‘‘ + ‘}‘; } }
编写UserDao接口
package com.gh.dao; import com.gh.entity.Login; import java.util.List; public interface UserDao { List<Login> findAll() throws Exception; void insertUser(Login login) throws Exception; void deleteById(Integer id) throws Exception; List<Login> selectByName(String s) throws Exception; }
编写UserDao.xml
<?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="com.gh.dao.UserDao"> <select id="findAll" resultType="Login"> select * from login </select> <insert id="insertUser" parameterType="Login"> insert into login values (null,#{login_name},#{password},#{phone}) </insert> <delete id="deleteById" parameterType="java.lang.Integer"> delete from Login where login_id=#{assd} </delete> <select id="selectByName" resultType="Login"> select * from Login where Login_name like "%${value}%" </select> </mapper>
编写测试类
package model; import com.gh.dao.UserDao; import com.gh.entity.Login; 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.apache.log4j.Logger; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.io.Reader; import java.util.List; public class TestMybatis { Logger logger = Logger.getLogger(TestMybatis.class); private SqlSessionFactory factory = null; @Before public void init() { try { //手动加载核心配置文件 Reader resource = Resources.getResourceAsReader("sqlMapConfig.xml"); factory = new SqlSessionFactoryBuilder().build(resource); } catch (IOException e) { e.printStackTrace(); } } @Test public void se() { SqlSession session = factory.openSession(); UserDao dao = session.getMapper(UserDao.class); try { List<Login> list = dao.findAll(); logger.debug(list); } catch (Exception e) { e.printStackTrace(); } } @Test public void test1() { SqlSession session = factory.openSession(); UserDao dao = session.getMapper(UserDao.class); Login login = new Login(); login.setLogin_name("sss"); login.setPassword("sss"); login.setPhone("15394280152"); try { dao.insertUser(login); session.commit(); } catch (Exception e) { e.printStackTrace(); } } @Test public void test2() { SqlSession session = factory.openSession(); //获取接口的代理对象 UserDao dao = session.getMapper(UserDao.class); try { dao.deleteById(112); session.commit(); } catch (Exception e) { e.printStackTrace(); } } @Test public void test3() { SqlSession session = factory.openSession(); UserDao dao = session.getMapper(UserDao.class); try { List<Login> list = dao.selectByName("o"); System.out.println(list); } catch (Exception e) { e.printStackTrace(); } } }
#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value.
parameterType:指定输入参数类型,mybatis通过ognl从输入对象中获取参数值拼接在sql中。
resultType:指定输出结果类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。
Mapper动态代理方式开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
Mapper接口开发需要遵循以下规范:
1、 Mapper.xml文件中的namespace与mapper接口的路径相同。
2、 Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
3、 Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
4、 Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
resultType可以指定pojo将查询结果映射为pojo,但需要pojo的属性名和sql查询的列名一致方可映射成功。
如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系 ,resultMap实质上还需要将查询结果映射到pojo对象中。
resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojo和list实现一对一查询和一对多查询。
<resultMap id="findco" type="User"> <id column="uid" property="id" javaType="java.lang.Integer"></id> <result column="name" property="name" javaType="java.lang.String"></result> <result column="age" property="age" javaType="java.lang.Integer"></result> <result column="sex" property="sex" javaType="java.lang.String"></result> <result column="address" property="address" javaType="java.lang.String"></result> <association property="score" javaType="Score"> <id column="sid" property="id" javaType="java.lang.Integer"></id> <result column="score" property="score" javaType="java.lang.Double"></result> <result column="u_id" property="u_id" javaType="java.lang.Integer"></result> </association> </resultMap>
查询语句:
<select id="findUserAndScore" resultMap="findco"> select *,user.id as uid,score.id as sid from user,score where user.id=score.u_id; </select>
封装实体:
@Getter @Setter @ToString public class User implements Serializable { private Integer id; private String name; private Integer age; private String sex; private String address; private Score score; }
<resultMap id="UserAndScores" type="User"> <id column="uid" property="id"/> <result column="name" property="name"/> <result column="age" property="age"/> <result column="sex" property="sex"/> <result column="address" property="address"/> <!--collection指的是一对多 javaType:当前属性的什么类型 ofType:集合中装的是什么类型--> <collection property="scores" ofType="Score" select="findByUserId" column="tid"> <id column="sid" property="id"/> <id column="score" property="score"/> <id column="u_id" property="u_id"/> </collection> </resultMap>
如果是简单数据类型,必须是value
如果是接收类型list集合,test里面只能写list
<select id="findById" resultType="user" parameterType="int"> select * from user where 1=1 <if test="value!=null"> and id = #{value} </if> </select>
<where >可以自动处理第一个and。
<select id="findById" resultType="user" parameterType="int"> select * from user <where> <if test="value!=null"> and id = #{value} </if> </where> </select>
<foreach>遍历元素
<if test="list!=null and list.size()!=0"> where id between <!--collection代表需要遍历的集合 index:索引 item:每一条元素 open:开始内容 close:结束内容 separate:分隔符 --> <foreach collection="list" index="i" item="item" separator="and"> #{item} </foreach> </if>
可以将公共SQL语句抽离出去
<sql id="findAll1"> select * from user </sql>
使用include引入sql片段
<include refid="findAll1"/>
导入延迟加载所需的两个包 ,导入cglib以及asm的jar包
在sqlMapConfig.xml中配置
<settings> <!-- 延迟加载开关 --> <setting name="lazyLoadingEnabled" value="true"/> <!-- 当设置为true的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载。 --> <setting name="aggressiveLazyLoading" value="false"/> </settings>
编写延迟加载sql语句
select代表要查询的语句,column代表传递的参数
<collection property="scores" ofType="Score" select="findByUserId" column="tid"> <id column="sid" property="id"/> <id column="score" property="score"/> <id column="u_id" property="u_id"/> </collection>
延迟加载sql
<select id="findByUserId" resultType="Score"> select *,id as sid from score where u_id=#{u_id} </select>
一级缓存是针对每一个sqlSession进行缓存。每个sqlSession对象中使用Map存储一级缓存数据,sqlSession对象销毁其中一级缓存数据不存在了。sqlSession与SqlSession之间的一级缓存互相不影响。
map中存储了sql执行查询的结果集(java对象)。
二级缓存是针对每个mapper相同 的namespace进行缓存。每个SqlSession都要调用mapper下的sql语句,在mapper级别设置了二级缓存的数据结构map,每个mapper对应一个map数据结构,map中存储了二级缓存的数据,存储了sql执行查询的结果集(java对象)。
每个SqlSession都可以访问到二级缓存中的数据,sqlsession对象销毁mapper中的二级缓存数据仍然存在。
原文:https://www.cnblogs.com/fqh2020/p/14961556.html