mybatis中的接口代理机制及其使用
mybatis 中的接口代理类机制,mybatis 框架中使用了动态代理的设计模式,让我们可以不用写,对应xxxmapper.java 接口的实现类,而是通过动态代理的方式,让mybatis 自动为我们生成对应实现了该 xxxmapper.java接口的实现类,这个动态代理实现的类,我们可以直接使用。
核心代码:
// 获取到 sqlsessionfactorybuilder sqlsessionfactorybuilder sqlsessionfactorybuilder = new sqlsessionfactorybuilder(); // 获取到sqlsessionfactory 对象 // sqlsessionfactory对象,一个sqlsessionfactory对应一个 environment, 一个environment通常是一个数据库 sqlsessionfactory sessionfactory = sqlsessionfactorybuilder.build(resources.getresourceasstream("mybatis-config.xml"), "mybatis"); // 获取到 salsession 会话,一次会话一个 sqlsession sqlsession = sessionfactory.opensession(); car car = new car(null, "999", "奥迪", 3.0, "2000-10-10", "新能源"); // 面向接口编程,获取接口的代理对象,也就是接口的实现类,实现类该接口中的方法 // 需要注意的是参数的 xxxmapper.class 和 返回值是保持一致的。 xxxmapper mapper = sqlsession.getmapper(xxxmapper.class); mapper.xxx(); // 执行的是该xxxmapper接口中的方法
// 获取到 salsession 会话,一次会话一个 sqlsession sqlsession = sessionfactory.opensession(); car car = new car(null, "999", "奥迪", 3.0, "2000-10-10", "新能源"); // 面向接口编程,获取接口的代理对象,也就是接口的实现类,实现类该接口中的方法 // 需要注意的是参数的 xxxmapper.class 和 返回值是保持一致的。 xxxmapper mapper = sqlsession.getmapper(xxxmapper.class); mapper.xxx(); // 执行的是该xxxmapper接口中的方法
使用以上代码的前提是:xxxmapper.xml 文件中的 namespace
必须和 dao(mapper)
接口的全限定名称一致,id
必须和 dao(mapper)
接口中方法名一致。
比如:我们这里的是:
carmappe.xml
xxxmapper.xml 文件中的 namespace
必须和 dao(mapper)
接口的全限定名称一致
对应的接口上的方法名,id 必须
和 dao(mapper)
接口中方法名一致。
使用的是 pojo 属性类赋值的话,#{} 的括号中的值,必须是 pojo类当中的属性名,比如这里我们用的是 car ,则#{}括号中的值,则必须是 car 的属性名。同时 #{} 括号中一定要有值(就算只有一个参数,也要有值(随便写都要有值),才行,不然编译无法通过)
实操
下面我们使用 mybatis 的接口代理机制,对数据库进行crud,(增删改查)的操作。
1.准备工作
数据表结构的设计,数据表名为:t_car
t_car 表中的数据信息:
在pom.xml
文件当中配置相关的依赖的 jar 包如下:
<?xml version="1.0" encoding="utf-8"?> <project xmlns="http://maven.apache.org/pom/4.0.0" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="http://maven.apache.org/pom/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelversion>4.0.0</modelversion> <groupid>com.rainbowsea</groupid> <artifactid>mybatis-005-crud-blog</artifactid> <version>1.0-snapshot</version> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> </properties> <dependencies> <!-- mybatis 的依赖--> <dependency> <groupid>org.mybatis</groupid> <artifactid>mybatis</artifactid> <version>3.5.10</version> </dependency> <!-- mysql --> <dependency> <groupid>mysql</groupid> <artifactid>mysql-connector-java</artifactid> <version>8.0.30</version> </dependency> <dependency> <groupid>junit</groupid> <artifactid>junit</artifactid> <version>4.13.2</version> <scope>test</scope> </dependency> <!-- 引入 logback的依赖,这个日志框架实现了slf4j 规范--> <dependency> <groupid>ch.qos.logback</groupid> <artifactid>logback-classic</artifactid> <version>1.2.11</version> </dependency> </dependencies> </project>
配置 logback 的配置文件,用于打印显示,我们的日志信息,方便我们查看我们的运行过程,效果。
<?xml version="1.0" encoding="utf-8"?> <configuration debug="false"> <!-- 控制台输出 --> <appender name="stdout" class="ch.qos.logback.core.consoleappender"> <encoder class="ch.qos.logback.classic.encoder.patternlayoutencoder"> <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--> <pattern>%d{yyyy-mm-dd hh:mm:ss.sss} [%thread] %-5level %logger{50} - %msg%n</pattern> </encoder> </appender> <!--mybatis log configure--> <logger name="com.apache.ibatis" level="trace"/> <logger name="java.sql.connection" level="debug"/> <logger name="java.sql.statement" level="debug"/> <logger name="java.sql.preparedstatement" level="debug"/> <!-- 日志输出级别,logback日志级别包括五个:trace < debug < info < warn < error --> <root level="debug"> <appender-ref ref="stdout"/> <appender-ref ref="file"/> </root> </configuration>
配置 mybatis 的核心配置文件,
<?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> <!-- 使用 <package> 还可以将这个包下的所有的类的全部自动起别名,别名就是简名,不区分大小写 --> <package name="com.rainbowsea.mybatis.pojo"/> </typealiases> <environments default="mybatis"> <environment id="mybatis"> <!-- managed 没有用第三框架管理的话,都是会被提交的,没有事务上的管理了 --> <transactionmanager type="jdbc"/> <datasource type="pooled"> <property name="driver" value="com.mysql.cj.jdbc.driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/> <property name="username" value="root"/> <property name="password" value="mysql123"/> </datasource> </environment> </environments> <mappers> <!-- 这里也是可以使用 package 包名扫描,但是同样的:对应接口路径要一致,接口名一致--> <mapper resource="carmapper.xml"></mapper> </mappers> </configuration>
对照 t_car 创建的orm 映射的 car 类
注意:在mybatis 当中对应的orm ,一般在框架里对应的 bean实体类,一定要实现该 set 和 get 方法以及无参数构造方法,无法框架无法使用反射机制,进行操作 。
建议用包装类,这样可以防止 null的问题,因为(简单类型 int num = null ,是不可以赋值为 null)的编译无法通过
package com.rainbowsea.mybatis.pojo; public class car { // 数据库表当中的字段应该和pojo类的属性一一对应 // 建议使用包装类,这样可以防止null的问题 private long id; private string carnum; private string brand; private double guideprice; private string producetime; private string cartype; public car() { } public car(long id, string carnum, string brand, double guideprice, string producetime, string cartype) { this.id = id; this.carnum = carnum; this.brand = brand; this.guideprice = guideprice; this.producetime = producetime; this.cartype = cartype; } @override public string tostring() { return "car{" + "id=" + id + ", carnum='" + carnum + '\'' + ", brand='" + brand + '\'' + ", guideprice=" + guideprice + ", producetime='" + producetime + '\'' + ", cattype='" + cartype + '\'' + '}'; } public long getid() { return id; } public void setid(long id) { this.id = id; } public string getcarnum() { return carnum; } public void setcarnum(string carnum) { this.carnum = carnum; } public string getbrand() { return brand; } public void setbrand(string brand) { this.brand = brand; } public double getguideprice() { return guideprice; } public void setguideprice(double guideprice) { this.guideprice = guideprice; } public string getproducetime() { return producetime; } public void setproducetime(string producetime) { this.producetime = producetime; } public string getcartype() { return cartype; } public void setcartype(string cattype) { this.cartype = cattype; } }
对应操作实现crud(增删改查)的接口(这里是:carmapper接口),在mybtis 当中 ,关于 crud(增删改查)操作的接口/实现类,都是 mapper
结尾的作为持久层,而在 mvc的三层架构中,则是以 dao
为后缀作为crud(增删改查)操作的接口/实现类。
package com.rainbowsea.mybatis.mapper; import com.rainbowsea.mybatis.pojo.car; import java.util.list; public interface carmapper { /** * 新增 car * @param car * @return */ int insert(car car); /** * 根据id 删除 car * @param id * @return */ int deletebyid(long id); /** * 修改汽车信息 * @param car * @return */ int update(car car); /** * 根据id查询汽车信息 * @param id * @return */ car selectbyid(long id); /** * 获取所有的汽车信息 * @return */ list<car> selectall(); }
2.insert 增加操作
对应 carmapper 接口中的 insert( ) 抽象方法。
public interface carmapper { /** * 新增 car * @param car * @return */ int insert(car car); }
对应 carmapper.xml sql语句映射文件,上编写 insert 插入的 sql语句。
<?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 一定要是:对应的接口的全限定类名--> <mapper namespace="com.rainbowsea.mybatis.mapper.carmapper"> <!-- id 要是 namespace 对应接口上的方法名: --> <insert id="insert" parametertype="com.rainbowsea.mybatis.pojo.car"> insert into t_car values(null,#{carnum},#{brand},#{guideprice},#{producetime},#{cartype}) </insert> </mapper>
java当中编程运行程序:
注意:因为是对数据库进行了修改,所以需要 commit() 提交给数据库,以及 close() 关闭资源
package com.rainbowsea.mybatis.test; import com.rainbowsea.mybatis.mapper.carmapper; import com.rainbowsea.mybatis.pojo.car; 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.test; import java.io.ioexception; public class carmappertest { @test public void testinsert() throws ioexception { // 获取到 sqlsessionfactorybuilder sqlsessionfactorybuilder sqlsessionfactorybuilder = new sqlsessionfactorybuilder(); // 获取到sqlsessionfactory 对象 // sqlsessionfactory对象,一个sqlsessionfactory对应一个 environment, 一个environment通常是一个数据库 sqlsessionfactory sessionfactory = sqlsessionfactorybuilder.build(resources.getresourceasstream("mybatis-config.xml"), "mybatis"); // 获取到 salsession 会话,一次会话一个 sqlsession sqlsession = sessionfactory.opensession(); car car = new car(null, "999", "奥迪", 3.0, "2000-10-10", "新能源"); // 面向接口编程,获取接口的代理对象,也就是接口的实现类,实现类该接口中的方法 carmapper mapper = sqlsession.getmapper(carmapper.class); int count = mapper.insert(car); system.out.println(count); sqlsession.commit(); sqlsession.close(); } }
3.delete 删除操作
根据 id 删除一条记录,删除id为 124的一条记录。
对应 carmapper 接口中的 deletebyid( long id) 抽象方法。
public interface carmapper { /** * 新增 car * @param car * @return */ int insert(car car); /** * 根据id 删除 car * @param id * @return */ int deletebyid(long id); }
对应 carmapper.xml sql语句映射文件,上编写 delete 删除的 sql语句。
使用以上代码的前提是:xxxmapper.xml 文件中的 namespace
必须和 dao(mapper)
接口的全限定名称一致,id
必须和 dao(mapper)
接口中方法名一致。
<?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 一定要是:对应的接口的全限定类名--> <mapper namespace="com.rainbowsea.mybatis.mapper.carmapper"> <!-- 如果只有一个参数需要传的话,#{} 括号中的值,可以随便写,但最后见名知意--> <delete id="deletebyid" > delete from t_car where id=#{id} </delete> </mapper>
java当中编程运行程序:
注意:因为是对数据库进行了修改,所以需要 commit() 提交给数据库,以及 close() 关闭资源
删除id为 124的一条记录。
import org.junit.test; import java.io.ioexception; public class carmappertest { @test public void testdeletebyid() throws ioexception { // 获取到 sqlsessionfactorybuilder sqlsessionfactorybuilder sqlsessionfactorybuilder = new sqlsessionfactorybuilder(); // 获取到sqlsessionfactory 对象 // sqlsessionfactory对象,一个sqlsessionfactory对应一个 environment, 一个environment通常是一个数据库 sqlsessionfactory sessionfactory = sqlsessionfactorybuilder.build(resources.getresourceasstream("mybatis-config.xml"), "mybatis"); // 获取到 salsession 会话,一次会话一个 sqlsession sqlsession = sessionfactory.opensession(); // 面向接口编程,获取接口的代理对象,也就是接口的实现类,实现类该接口中的方法 carmapper mapper = sqlsession.getmapper(carmapper.class); // 删除id为 124的一条记录。 int count = mapper.deletebyid(124l); sqlsession.commit(); // 提交给数据库 sqlsession.close(); // 关闭资源 system.out.println(count); } }
4.update 修改操作
根据 id 修改记录信息。
将 id 为 128的 brand 改为小米su7, guide_price 改为 21.00 , 时间改为 2024-03-28
对应 carmapper 接口中的 update( ) 抽象方法。
package com.rainbowsea.mybatis.mapper; import com.rainbowsea.mybatis.pojo.car; import java.util.list; public interface carmapper { /** * 修改汽车信息 * @param car * @return */ int update(car car); }
对应 carmapper.xml sql语句映射文件,上编写 update 修改的 sql语句。
使用以上代码的前提是:xxxmapper.xml 文件中的 namespace
必须和 dao(mapper)
接口的全限定名称一致,id
必须和 dao(mapper)
接口中方法名一致。
<?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 一定要是:对应的接口的全限定类名--> <mapper namespace="com.rainbowsea.mybatis.mapper.carmapper"> <!-- id 要是 namespace 对应接口上的方法名: --> <update id="update"> update t_car set car_num=#{carnum}, brand=#{brand}, guide_price=#{guideprice}, produce_time=#{producetime}, car_type=#{cartype} where id = #{id} </update> </mapper>
java当中编程运行程序:
注意:因为是对数据库进行了修改,所以需要 commit() 提交给数据库,以及 close() 关闭资源
将 id 为 128的 brand 改为小米su7, guide_price 改为 21.00 , 时间改为 2024-03-28
import com.rainbowsea.mybatis.mapper.carmapper; import com.rainbowsea.mybatis.pojo.car; 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.test; import java.io.ioexception; public class carmappertest { @test public void testupdate() throws ioexception { // 获取到 sqlsessionfactorybuilder sqlsessionfactorybuilder sqlsessionfactorybuilder = new sqlsessionfactorybuilder(); // 获取到sqlsessionfactory 对象 // sqlsessionfactory对象,一个sqlsessionfactory对应一个 environment, 一个environment通常是一个数据库 sqlsessionfactory sessionfactory = sqlsessionfactorybuilder.build(resources.getresourceasstream("mybatis-config.xml"), "mybatis"); // 获取到 salsession 会话,一次会话一个 sqlsession sqlsession = sessionfactory.opensession(); car car = new car(128l, "999", "小米su7", 21.0, "2022-03-28", "新能源"); // 面向接口编程,获取接口的代理对象,也就是接口的实现类,实现类该接口中的方法 carmapper mapper = sqlsession.getmapper(carmapper.class); int count = mapper.update(car); sqlsession.commit(); // 提交给数据库 sqlsession.close(); } }
5.select 查询一条记录操作
根据 id 查询一条记录。
查询 id 为 130 的一条记录。
对应 carmapper 接口中的 selectbyid ( long id) 抽象方法。
package com.rainbowsea.mybatis.mapper; import com.rainbowsea.mybatis.pojo.car; import java.util.list; public interface carmapper { /** * 根据id查询汽车信息 * @param id * @return */ car selectbyid(long id); }
对应 carmapper.xml sql语句映射文件,上编写 select 查询 的 sql语句。
使用以上代码的前提是:xxxmapper.xml 文件中的 namespace
必须和 dao(mapper)
接口的全限定名称一致,id
必须和 dao(mapper)
接口中方法名一致。
需要注意的是:查询是会返回结果集的,所以我们需要在 <select> 查询标签当中,通过 resulttype 属性指定返回的类型(如果没有用别名机制的话,要用全限定类名(带包名的)) 。
同时由于我们的数据表的字段的命名方式是下划线 ,部分数据表的字段名与我们设置的 orm 映射的pojo类的属性名不一致,需要将他们二者的名字保持一致,所以我们需要使用 as 定义别名,不然无法将对应数据表中的值,赋值到 对应的 pojo的类当中(这里是 car 类当中)
<?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 一定要是:对应的接口的全限定类名--> <mapper namespace="com.rainbowsea.mybatis.mapper.carmapper"> <!-- id 要是 namespace 对应接口上的方法名: --> <select id="selectbyid" resulttype="com.rainbowsea.mybatis.pojo.car"> select id, car_num as carnum, brand, guide_price as guideprice, produce_time as producetime, car_type as cartype from t_car where id = #{id} </select> </mapper>
java当中编程运行程序:
注意:因为我们仅仅是查询数据表中的信息,不涉及到对数据表的修改,删除操作,所以无需提交数据库commit,只要 close() 关闭资源就可以了
查询 id 为 130 的一条记录。
import com.rainbowsea.mybatis.mapper.carmapper; import com.rainbowsea.mybatis.pojo.car; 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.test; import java.io.ioexception; public class carmappertest { @test public void testselectbyid() throws ioexception { // 获取到 sqlsessionfactorybuilder sqlsessionfactorybuilder sqlsessionfactorybuilder = new sqlsessionfactorybuilder(); // 获取到sqlsessionfactory 对象 // sqlsessionfactory对象,一个sqlsessionfactory对应一个 environment, 一个environment通常是一个数据库 sqlsessionfactory sessionfactory = sqlsessionfactorybuilder.build(resources.getresourceasstream("mybatis-config.xml"), "mybatis"); // 获取到 salsession 会话,一次会话一个 sqlsession sqlsession = sessionfactory.opensession(); // 面向接口编程,获取接口的代理对象,也就是接口的实现类,实现类该接口中的方法 carmapper mapper = sqlsession.getmapper(carmapper.class); car car = mapper.selectbyid(130l); system.out.println(car); sqlsession.close(); } }
6.select 查询多条记录操作
查询t_car 数据表中的所有信息。
对应 carmapper 接口中的 selectall( long id) 抽象方法。返回的是一个list 集合
package com.rainbowsea.mybatis.mapper; import com.rainbowsea.mybatis.pojo.car; import java.util.list; public interface carmapper { /** * 获取所有的汽车信息 * @return */ list<car> selectall(); }
对应 carmapper.xml sql语句映射文件,上编写 select 查询 的 sql语句。
使用以上代码的前提是:xxxmapper.xml 文件中的 namespace
必须和 dao(mapper)
接口的全限定名称一致,id
必须和 dao(mapper)
接口中方法名一致。
需要注意的是:查询是会返回结果集的,所以我们需要在 <select> 查询标签当中,通过 resulttype 属性指定返回的类型(如果没有用别名机制的话,要用全限定类名(带包名的)) 。
同时由于我们的数据表的字段的命名方式是下划线 ,部分数据表的字段名与我们设置的 orm 映射的pojo类的属性名不一致,需要将他们二者的名字保持一致,所以我们需要使用 as 定义别名,不然无法将对应数据表中的值,赋值到 对应的 pojo的类当中(这里是 car 类当中)
<?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 一定要是:对应的接口的全限定类名--> <mapper namespace="com.rainbowsea.mybatis.mapper.carmapper"> <!-- id 要是 namespace 对应接口上的方法名: --> <select id="selectall" resulttype="com.rainbowsea.mybatis.pojo.car"> select id, car_num as carnum, brand, guide_price as guideprice, produce_time as producetime, car_type as cartype from t_car </select> </mapper>
java当中编程运行程序:
注意:因为我们仅仅是查询数据表中的信息,不涉及到对数据表的修改,删除操作,所以无需提交数据库commit,只要 close() 关闭资源就可以了
查询 t_car 数据表中的所有记录。
import com.rainbowsea.mybatis.mapper.carmapper; import com.rainbowsea.mybatis.pojo.car; 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.test; import java.io.ioexception; import java.util.list; public class carmappertest { @test public void testselectall() throws ioexception { // 获取到 sqlsessionfactorybuilder sqlsessionfactorybuilder sqlsessionfactorybuilder = new sqlsessionfactorybuilder(); // 获取到sqlsessionfactory 对象 // sqlsessionfactory对象,一个sqlsessionfactory对应一个 environment, 一个environment通常是一个数据库 sqlsessionfactory sessionfactory = sqlsessionfactorybuilder.build(resources.getresourceasstream("mybatis-config.xml"), "mybatis"); // 获取到 salsession 会话,一次会话一个 sqlsession sqlsession = sessionfactory.opensession(); // 面向接口编程,获取接口的代理对象,也就是接口的实现类,实现类该接口中的方法 carmapper mapper = sqlsession.getmapper(carmapper.class); list<car> cars = mapper.selectall(); cars.foreach(car -> { system.out.println(car); }); sqlsession.close(); } }
总结
// 获取到 salsession 会话,一次会话一个 sqlsession sqlsession = sessionfactory.opensession(); car car = new car(null, "999", "奥迪", 3.0, "2000-10-10", "新能源"); // 面向接口编程,获取接口的代理对象,也就是接口的实现类,实现类该接口中的方法 // 需要注意的是参数的 xxxmapper.class 和 返回值是保持一致的。 xxxmapper mapper = sqlsession.getmapper(xxxmapper.class); mapper.xxx(); // 执行的是该xxxmapper接口中的方法
使用以上代码的前提是:xxxmapper.xml 文件中的 namespace
必须和 dao(mapper)
接口的全限定名称一致,id
必须和 dao(mapper)
接口中方法名一致。
注意:因为是对数据库进行了修改,删除,改动了,所以需要 commit() 提交给数据库,以及 close() 关闭资源
需要注意的是:查询是会返回结果集的,所以我们需要在 <select> 查询标签当中,通过 resulttype 属性指定返回的类型(如果没有用别名机制的话,要用全限定类名(带包名的)) 。
同时由于我们的数据表的字段的命名方式是下划线 ,部分数据表的字段名与我们设置的 orm 映射的pojo类的属性名不一致,需要将他们二者的名字保持一致,所以我们需要使用 as 定义别名,不然无法将对应数据表中的值,赋值到 对应的 pojo的类当中(这里是 car 类当中)
注意:因为我们仅仅是查询数据表中的信息,不涉及到对数据表的修改,删除操作,所以无需提交数据库commit,只要 close() 关闭资源就可以了。
如果只有一个参数需要传的话,#{} 括号中的值,可以随便写(#{}括号的值不能空着,不然不编译无法通过),但最好见名知意。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论