MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJO映射成数据库中的记录。原生的jdbc操作存在大量的重复性代码(如注册驱动,创建连接,创建statement,结果集检测等)。框架的作用就是把这些繁琐的代码封装,这样可以让程序员专注于sql语句本身
mybatis官方文档:http://www.mybatis.org/mybatis-3/zh/index.html
JDK 1.8.0,Eclipse oxygen,数据库 Mysql+Navicat。
接下来在webContent-> WEB-INF->lib文件下复制所有包(如果没有lib文件夹的童鞋就自己照着这个路径新建一个就好)。然后选中这些所有的包右键选择Build Path->add to Bulid path,这样你就导入所有的包啦。
一般命名为:mybatis-config.xml
在后面整合mybatis+spring后命名:spring-dao.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--这个干啥不清楚,会从网站下载mybatis-3-mapper.dtd文件,此xml文件就可以使用这些mybatis标签来配置文件 -->
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--可以通过log4j查看Mybatis执行的sql语句,以及执行情况。后面再测试中还会提到 -->
<settings>
<setting name="lazyLoadingEnabled" value="false" />
<setting name="logImpl" value="LOG4J" />
setting name="safeRowBoundsEnabled" value="true"
</settings>
<!--environments:配置MyBatis环境,可以配置过多个运行环境,
但是SqlSessionFactory只能选择一个运行环境(default=环境ID id=每个environment元素的环境 ) -->
<environments default="TestConnect">
<environment id="TestConnect">
<!--事务管理器的配置(比如:type=”JDBC”) -->
<transactionManager type="JDBC"></transactionManager>
<!--数据源的配置(比如:type=”POOLED”)type=[ UNPOOLED | POOLED | JNDI ] -->
<dataSource type="POOLED">
<!--与传统的jdbc一样,需要这4个数据 -->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="*******"/>
</dataSource>
</environment>
</environments>
<!--扫描,加载 .xml的mapper文件 -->
<mappers>
<mapper resource="com/hg/mapper/UserMapper.xml"/>
</mappers>
</configuration>
关于mybatis中environments的配置大神详细说明:https://blog.csdn.net/mqf163/article/details/52514186
使用Mysql+Navicat
这里为了演示效果就就简单的新建了一张user_test表,表中的属性也很简单:分别是id,username,psw属性。为什么这里着重强调了表的命名,因为框架中的命名会涉及到框架的自动扫描等等(个人理解)。所以在很多情况下当我们命名符合规范时,会对我们的开发提供极大的便利。
实体类中的属性名字与数据库字段一致时,Mybatis可以完成完成自动映射。所以刚刚提到了要使用数据库字段的名字来对模型类进行命名。所以在com.hg.pojo下新建一个UserPojo的类。
public class UserPojo { private int id; private String username; private String psw;
@Override public String toString() { return "UserPojo [id=" + id + ", username=" + username + ", psw=" + psw + "]"; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPsw() { return psw; } public void setPsw(String psw) { this.psw = psw; } /*public UserPojo(int id, String username, String psw) { super(); this.id = id; this.username = username; this.psw = psw; }*/
}
其实没什么好说的,就是让私有属性要和数据库字段相同,然后生成所有属性的set和get方法。当然大家可以看到我在后面增加了一个带参数的构造函数并且注释掉了,因为记得无意间看视频中提起过,mybatis要调用模型类的无参的构造函数来新建一个类,我就做了一个实验添加一个有参的构造函数在内中,瞬间mybatis就开始报错了,注释掉就好了。所以在这里提醒那些不喜欢添加的无参构造函数的小朋友,**一定要添加无参构造函数!一定要添加无参构造函数!一定要添加无参构造函数!**否则就别写有参的构造函数!
当然相信有很皮的小伙伴要问了,必须要私有属性要和数据库字段相同吗?我不想一样可以吗,当然可以,而且我和你一样的皮做了关于命名不同的实验一个实验(接下来的内容希望你在成功的搭建好mybatis后再尝试)。
解决数据中实体类中的属性名与数据库字段不一致的解决方案。
public class UserPojo1 { private int id; private String Uusername; private String Upsw;
public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUusername() { return Uusername; } public void setUusername(String uusername) { Uusername = uusername; } public String getUpsw() { return Upsw; } public void setUpsw(String upsw) { Upsw = upsw;
}
@Override
public String toString() {
return “UserPojo1111111111 [id=” + id + “, Uusername=” + Uusername + “, Upsw=” + Upsw + “]”;
}}
<select id="selectAll1" resultType="com.hg.pojo.UserPojo1">
select
id ,
username as Uusername,
psw as Upsw
from user_test
</select>
左边的是数据库中的字段名字,右边是你的pojo类中的属性名,这样同样也能完成功能。但是我们思考一个问题,如果每次都要在增删改查的是否这么强制转换是不是未免太麻烦了?框架的本质不就是为程序员省去大量重复又冗余的代码。在每个sql语句中有这个强制的时间,不如去把实体类的属性名改的和数据库一样。即使我都这么说了,你还要这么皮的坚持使用你刚刚的实体类,好吧!你赢了,mybatis还真有解决办法解决。
2. 使用resultMap指定映射,也可以不需要强制转化
<resultMap type="com.hg.pojo.UserPojo1" id="UserPojo1">
<id column="id" property="id"/>
<result column="username" property="Uusername"/>
<result column="psw" property="Upsw"/>
</resultMap>
<select id="selectAll2" resultMap="UserPojo1">
select * from user_test
</select>
其实关于resultMap其实还有很多可以说的,关于resultMap官方是这样介绍的。
后面的类型别名和高级结构留给大家自己去学习吧。
最后一种方式不是给那些皮皮的同学的,是为那些对于无论是数据库命名还是类中属性命名都一丝不苟的程序员们而准备的。
3. 开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射, 默认false。
这个需要回到最早的mybatis-config.xml中找到
<setting name="mapUnderscoreToCamelCase" value="true"/>
添加上后就不用广大朋友们再强制转换或者使用resultmap啦。
在强调一次是接口!接口!接口!小伙伴不要搞成类了哈。
在接口声明抽象方法 返回类型 输入属性
我在com.hg.dao的包下新建了一个UserMapper的接口,注意这里的命名后面要用到。代码如下:
public interface UserMapper { UserPojo selectById(int id); UserPojo selectById2(@Param(value="id")int id,@Param(value="psw")String psw);
List<UserPojo> selectAll(); int updataUser(UserPojo pojo); List<UserPojo1> selectAll1(); List<UserPojo1> selectAll2(); int insertUserpojo(List<UserPojo> list);
}
不光要记住接口名,每个抽象方法的名字, 返回类型, 输入属性的名字都很重要哈。
我在com.hg.mapper的包下新建了一个UserMapper.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.hg.dao.UserMapper”>
<resultMap type=“com.hg.pojo.UserPojo1” id=“UserPojo1”>
<id column=“id” property=“id”/>
<result column=“username” property=“Uusername”/>
<result column=“psw” property=“Upsw”/>
</resultMap>
<select id=“selectById” resultType=“com.hg.pojo.UserPojo”>
select * from user_test <where>id=#{ id}</where>
</select>
<select id="selectById2" resultType="com.hg.pojo.UserPojo">
select * from user_test <where>id=#{id} and psw=#{psw}</where>
</select>
<select id="selectAll" resultType="com.hg.pojo.UserPojo">
select * from user_test
</select>
<select id="selectAll1" resultType="com.hg.pojo.UserPojo1">
select
id ,
username as Uusername,
psw as Upsw
from user_test
</select>
<select id="selectAll2" resultMap="UserPojo1">
select * from user_test
</select>
<update id="updataUser" parameterType="com.hg.pojo.UserPojo" >
update user_test
<set>
<if test="username != null">username=#{username},</if>
<if test="psw != null">psw=#{psw}</if>
</set>
where id=#{id}
</update>
<insert id="insertUserpojo" parameterType="com.hg.pojo.UserPojo">
insert into user_test(username,psw) values
<foreach collection="list" item="user" separator=",">
(#{user.username}, #{user.psw})
</foreach>
</insert>
</mapper>
接下来就来到了mybatis的mapper的配置文件,这是最后一步啦。首先还是要强调一下命名规则,这个.xml文件的名字需要和上个定义的接口名相同都是UserMapper(我暂时还没找到名字不同的解决办法,但是在后面的框架整合后可以支持命名不同)。然后在mybatis中,映射文件中的namespace是用于绑定Dao接口的,即面向接口编程。mapper namespace=接口的相对路径。在mapper中可以使用如下标签:
这里我们就看看select,insert,update,delete,resultmap这几个标签。先说前面四个标签,学过数据库的同学很快就能明白是什么意思中,你要执行的什么操作就添加什么标签。然后在标签中添加id属性,id需要填什么呢?id就是你前面定义的接口方法名。这是官方文档中对标签select中所有属性的介绍:
这里我就说一下parameterType,resultType,resultMap属性。parameterType是指定传入参数,但是mybatis可以自动的识别出传入参数的类型,所以要是不清楚传入传输类型,这个属性就不用填写。接下来就是resultType,resultMap,他们长得很像奥,他们也都是指定返回类型。但是看到官方文档中说了他们不能同时存在,但是也不能都没有不然就会在运行时报错。还记得我们要在数据库中和类中转换的第二种的方法吗?你可以指定返回这个你已经定义的resultMap,当然resultMap的功能可远不如此,这里就先不介绍啦。另外只用resultType就是返回任何类型,但是要具体指定。另外着重强调的是如果返回的注意如果是集合情形,那应该是集合可以包含的类型,而不能是集合本身(这个怎么理解啊,就是我们返回的List,我们的resultMap不是List而应该是UserPojo)。
接下来来看看insert,update,delete的标签的属性。
哈哈很多属性我还没用过QAQ,所以就不讲啦。但是这些操作返回的是int的类型,1代表操作成功,0代表操作失败。
在完成标签属性的配置后,我们就可以写sql语句啦,可以看到在传入参数是用的#{}的方式。在接口定义的时候时定义的名字相同时,可以直接使用#{接口中定义传参的属性名}。但是会存在顺序,名字不同等等的情况,这个时候我们需要在接口中加上**@Param(“参数名”)**,表示给参数命名,名称就是括号中的内容。
UserPojo selectById2(@Param(value="id")int id,@Param(value="psw")String psw);
@Param注解的作用是给参数命名,参数命名后就能根据名字得到参数值,正确的将参数传入sql语句中 。
当然细心的你已经发现了set,if,foreach等等的标签,这些被称作动态sql语句,是我觉得mybatis最神奇的地方!比如你准备update数据表,但是你不知道需要更改的是哪个属性,所以你准备把所有需要更新的可能都列举一遍(username+psw或者username或者psw,这只是一个三个属性的表就有三种可能,如果属性更多,你是不是都要哭了)。但是如果我们加入if,set这两个标签,我们只需要写上一句update就可以实现所有的更新。
<update id="updataUser" parameterType="com.hg.pojo.UserPojo" >
update user_test
<set>
<if test="username != null">username=#{
username},</if>
<if test="psw != null">psw=#{
psw}</if>
</set>
where id=#{
id}
</update>
还有我们可以批量的增加数据哟:
<insert id="insertUserpojo" parameterType="com.hg.pojo.UserPojo">
insert into user_test(username,psw) values
<foreach collection="list" item="user" separator=",">
(#{
user.username}, #{
user.psw})
</foreach>
</insert>
mybatis真的为了程序员们操碎了心,每一处的细节都优化到极致。比如我们在set标签中加入每个属性的判断,如果这个传入参数不为空就添加到sql语句中,为空亏不添加到sql语句中。mybatis甚至细致到可以帮你完成sql语句的清理工作:
<if test="username != null">username=#{
username},</if>
<if test="psw != null">psw=#{
psw}</if>
你想想会不会出现,第一句话执行但是第二句不执行的情况,那么现在sql语句是不是就变成了 update user_test username=#{username}, 这样的sql语句执行肯定会报错的,但是mybatis会自动检测到这里多了一个逗号,在后面处理掉这个逗号,返回你想要的结果。虽然不知道是怎么实现的,但是真的不得不感叹mybatis的强大,而且这也仅仅只是动态sql的小小的一部分。如果你想深入了解mybatis,可以参考mybatis的官方文档,我把它放在博客的开始的位置(mybatis的官方文档是被很多人好评的,即使你从未用过mybatis,看了文档后都能模仿出一个mybatis的工程)。
在测试开始前我们要回到我们最初的mybatis-config.xml配置文件中,我们需要让配置文件扫描我们的mapper映射文件,可以参考大神写得四种加载方法https://blog.csdn.net/tanga842428/article/details/79285957
<mappers>
<mapper resource="com/hg/mapper/UserMapper.xml"/>
</mappers>
在测试之前,我还要推荐使用log4j,这样我们能在控制台看到sql语句的生成,使用的方法也很简单。新建一个log4j.properties在里面添加如下内容:
log4j.rootLogger=DEBUG,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.org.apache=INFO
再到mybatis-config.xml配置文件添加如下代码:
<settings>
<setting name="lazyLoadingEnabled" value="false" />
<setting name="logImpl" value="LOG4J" />
</settings>
好啦现在开始我们的测试吧:
简单说下吧:首先我写了一个静态的加载(当然也可以封装到一个类中),每次调用这个类时就会加载这个方法。首先 通过Resources.getResourceAsStream(“mybatis-config.xml”)获取到配置文件的输入流,然后通过SqlSessionFactoryBuilder().build(in)创建SqlSessionFactory ,调用factory.openSession()获取SqlSession ,最后通过session.getMapper获取到我们的UserMapper接口,之后我们就可以调用接口中的方法来执行sql操作啦。注意两点哟:1:SqlSession 在每次用完后必须关闭,2:只要对数据库中的数据有操作的,切记一定要在最后提交session.commit(),否则数据库不会执行更新操作 。控制台不仅不会报错,还会还告诉你执行成功,但是在数据库中不执行任何操作。
public class MyTest { private static SqlSessionFactory factory=null; private static UserMapper dao=null; private static SqlSession session=null; static { InputStream in = null; try { in = Resources.getResourceAsStream("mybatis-config.xml"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } factory = new SqlSessionFactoryBuilder().build(in); session= factory.openSession(); dao= session.getMapper(UserMapper.class); }
public static void main(String[] args) throws IOException { //MyTest.test1();//测试selectAll方法 //MyTest.test2();//测试selectById方法 //MyTest.test3();//测试selectAll1方法 //MyTest.test4();//测试selectAll2方法 //MyTest.test5();//测试updataUser方法 //MyTest.test6();//批量insertUserpojo方法 //MyTest.test7();//测试selectById2方法 session.close(); } public static void test1() { // 通过新建pojo类的属性名与数据库列名相同 List<UserPojo> list = dao.selectAll(); System.out.println("selectAll" + list); } public static void test2() { System.out.println(dao.selectById(1).toString()); } public static void test3() { /*通过新建pojo类的属性名与数据库列名不相同 */ List<UserPojo1> list =dao.selectAll1(); System.out.println("selectAll1()"+list); } public static void test4() { /*2.使用resultMap指定映射*/ List<UserPojo1> list =dao.selectAll2(); System.out.println("selectAll2"+list); } public static void test5() { /* 使用动态sql语句 */ UserPojo pojo=new UserPojo(); pojo.setId(1); pojo.setPsw("更改密码hehe"); int state=dao.updataUser(pojo); System.out.println(state); session.commit(); /*切记一定要在最后提交session.commit(), 否则数据库不会执行更新操作,除了对查询操作, 其余对于数据有改动的都需要 session.commit();*/ } public static void test6() { UserPojo pojo=new UserPojo(); pojo.setUsername("1号人物"); pojo.setPsw("aaaaaaa"); UserPojo pojo1=new UserPojo(); pojo1.setUsername("2号人物"); pojo1.setPsw("bbbbbb"); UserPojo pojo2=new UserPojo(); pojo2.setUsername("3号人物"); pojo2.setPsw("cccccc"); List<UserPojo> list=new ArrayList<>(); list.add(pojo); list.add(pojo1); list.add(pojo2); System.out.println(dao.insertUserpojo(list)); session.commit(); } public static void test7() { UserPojo pojo=dao.selectById2(11, "aaaaaaa"); System.out.println(pojo.toString()); }
}
还记得文章开头说MyBatis 可以使用简单的 XML 或注解吗,那么mybatis的注解怎么使用呢?
@Delete("delete from user_test where id =#{id}")
int deletUser(int id);
对的!只需要在我们的接口中声明方法的时候加上注解,不用再去.xml中配置声明了。但是我个人现在还是觉得动态sql和resultmap比注解易读且方便,或许在未来更新换代的时候能提供更方便的注解模式。
至此本篇博客就到此为止啦,感谢老师和师兄们的热情帮助,让我顺利完成本篇博客!对代码还不清楚或者需要jar包的同学可以到https://github.com/tony-bryant/MyBatisSample下载源码来查看。作为一个才开始学习框架的菜鸟,很多原理以及实现不是很清楚,文中也会有有错误,如果发现错误希望能够帮我指出来,谢谢大家!
最后推荐两位大神的博客分别是MyBatis原理浅析+Mybatis之工作原理,感兴趣的同学可以去学习学习。
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJO映射成数据库中的记录。原生的jdbc操作存在大量的重复性代码(如注册驱动,创建连接,创建statement,结果集检测等)。框架的作用就是把这些繁琐的代码封装,这样可以让程序员专注于sql语句本身
mybatis官方文档:http://www.mybatis.org/mybatis-3/zh/index.html
JDK 1.8.0,Eclipse oxygen,数据库 Mysql+Navicat。
接下来在webContent-> WEB-INF->lib文件下复制所有包(如果没有lib文件夹的童鞋就自己照着这个路径新建一个就好)。然后选中这些所有的包右键选择Build Path->add to Bulid path,这样你就导入所有的包啦。
一般命名为:mybatis-config.xml
在后面整合mybatis+spring后命名:spring-dao.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--这个干啥不清楚,会从网站下载mybatis-3-mapper.dtd文件,此xml文件就可以使用这些mybatis标签来配置文件 -->
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--可以通过log4j查看Mybatis执行的sql语句,以及执行情况。后面再测试中还会提到 -->
<settings>
<setting name="lazyLoadingEnabled" value="false" />
<setting name="logImpl" value="LOG4J" />
setting name="safeRowBoundsEnabled" value="true"
</settings>
<!--environments:配置MyBatis环境,可以配置过多个运行环境,
但是SqlSessionFactory只能选择一个运行环境(default=环境ID id=每个environment元素的环境 ) -->
<environments default="TestConnect">
<environment id="TestConnect">
<!--事务管理器的配置(比如:type=”JDBC”) -->
<transactionManager type="JDBC"></transactionManager>
<!--数据源的配置(比如:type=”POOLED”)type=[ UNPOOLED | POOLED | JNDI ] -->
<dataSource type="POOLED">
<!--与传统的jdbc一样,需要这4个数据 -->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="*******"/>
</dataSource>
</environment>
</environments>
<!--扫描,加载 .xml的mapper文件 -->
<mappers>
<mapper resource="com/hg/mapper/UserMapper.xml"/>
</mappers>
</configuration>
关于mybatis中environments的配置大神详细说明:https://blog.csdn.net/mqf163/article/details/52514186
使用Mysql+Navicat
这里为了演示效果就就简单的新建了一张user_test表,表中的属性也很简单:分别是id,username,psw属性。为什么这里着重强调了表的命名,因为框架中的命名会涉及到框架的自动扫描等等(个人理解)。所以在很多情况下当我们命名符合规范时,会对我们的开发提供极大的便利。
实体类中的属性名字与数据库字段一致时,Mybatis可以完成完成自动映射。所以刚刚提到了要使用数据库字段的名字来对模型类进行命名。所以在com.hg.pojo下新建一个UserPojo的类。
public class UserPojo { private int id; private String username; private String psw;
@Override public String toString() { return "UserPojo [id=" + id + ", username=" + username + ", psw=" + psw + "]"; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPsw() { return psw; } public void setPsw(String psw) { this.psw = psw; } /*public UserPojo(int id, String username, String psw) { super(); this.id = id; this.username = username; this.psw = psw; }*/
}
其实没什么好说的,就是让私有属性要和数据库字段相同,然后生成所有属性的set和get方法。当然大家可以看到我在后面增加了一个带参数的构造函数并且注释掉了,因为记得无意间看视频中提起过,mybatis要调用模型类的无参的构造函数来新建一个类,我就做了一个实验添加一个有参的构造函数在内中,瞬间mybatis就开始报错了,注释掉就好了。所以在这里提醒那些不喜欢添加的无参构造函数的小朋友,**一定要添加无参构造函数!一定要添加无参构造函数!一定要添加无参构造函数!**否则就别写有参的构造函数!
当然相信有很皮的小伙伴要问了,必须要私有属性要和数据库字段相同吗?我不想一样可以吗,当然可以,而且我和你一样的皮做了关于命名不同的实验一个实验(接下来的内容希望你在成功的搭建好mybatis后再尝试)。
解决数据中实体类中的属性名与数据库字段不一致的解决方案。
public class UserPojo1 { private int id; private String Uusername; private String Upsw;
public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUusername() { return Uusername; } public void setUusername(String uusername) { Uusername = uusername; } public String getUpsw() { return Upsw; } public void setUpsw(String upsw) { Upsw = upsw;
}
@Override
public String toString() {
return “UserPojo1111111111 [id=” + id + “, Uusername=” + Uusername + “, Upsw=” + Upsw + “]”;
}}
<select id="selectAll1" resultType="com.hg.pojo.UserPojo1">
select
id ,
username as Uusername,
psw as Upsw
from user_test
</select>
左边的是数据库中的字段名字,右边是你的pojo类中的属性名,这样同样也能完成功能。但是我们思考一个问题,如果每次都要在增删改查的是否这么强制转换是不是未免太麻烦了?框架的本质不就是为程序员省去大量重复又冗余的代码。在每个sql语句中有这个强制的时间,不如去把实体类的属性名改的和数据库一样。即使我都这么说了,你还要这么皮的坚持使用你刚刚的实体类,好吧!你赢了,mybatis还真有解决办法解决。
2. 使用resultMap指定映射,也可以不需要强制转化
<resultMap type="com.hg.pojo.UserPojo1" id="UserPojo1">
<id column="id" property="id"/>
<result column="username" property="Uusername"/>
<result column="psw" property="Upsw"/>
</resultMap>
<select id="selectAll2" resultMap="UserPojo1">
select * from user_test
</select>
其实关于resultMap其实还有很多可以说的,关于resultMap官方是这样介绍的。
后面的类型别名和高级结构留给大家自己去学习吧。
最后一种方式不是给那些皮皮的同学的,是为那些对于无论是数据库命名还是类中属性命名都一丝不苟的程序员们而准备的。
3. 开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射, 默认false。
这个需要回到最早的mybatis-config.xml中找到
<setting name="mapUnderscoreToCamelCase" value="true"/>
添加上后就不用广大朋友们再强制转换或者使用resultmap啦。
在强调一次是接口!接口!接口!小伙伴不要搞成类了哈。
在接口声明抽象方法 返回类型 输入属性
我在com.hg.dao的包下新建了一个UserMapper的接口,注意这里的命名后面要用到。代码如下:
public interface UserMapper { UserPojo selectById(int id); UserPojo selectById2(@Param(value="id")int id,@Param(value="psw")String psw);
List<UserPojo> selectAll(); int updataUser(UserPojo pojo); List<UserPojo1> selectAll1(); List<UserPojo1> selectAll2(); int insertUserpojo(List<UserPojo> list);
}
不光要记住接口名,每个抽象方法的名字, 返回类型, 输入属性的名字都很重要哈。
我在com.hg.mapper的包下新建了一个UserMapper.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.hg.dao.UserMapper”>
<resultMap type=“com.hg.pojo.UserPojo1” id=“UserPojo1”>
<id column=“id” property=“id”/>
<result column=“username” property=“Uusername”/>
<result column=“psw” property=“Upsw”/>
</resultMap>
<select id=“selectById” resultType=“com.hg.pojo.UserPojo”>
select * from user_test <where>id=#{ id}</where>
</select>
<select id="selectById2" resultType="com.hg.pojo.UserPojo">
select * from user_test <where>id=#{id} and psw=#{psw}</where>
</select>
<select id="selectAll" resultType="com.hg.pojo.UserPojo">
select * from user_test
</select>
<select id="selectAll1" resultType="com.hg.pojo.UserPojo1">
select
id ,
username as Uusername,
psw as Upsw
from user_test
</select>
<select id="selectAll2" resultMap="UserPojo1">
select * from user_test
</select>
<update id="updataUser" parameterType="com.hg.pojo.UserPojo" >
update user_test
<set>
<if test="username != null">username=#{username},</if>
<if test="psw != null">psw=#{psw}</if>
</set>
where id=#{id}
</update>
<insert id="insertUserpojo" parameterType="com.hg.pojo.UserPojo">
insert into user_test(username,psw) values
<foreach collection="list" item="user" separator=",">
(#{user.username}, #{user.psw})
</foreach>
</insert>
</mapper>
接下来就来到了mybatis的mapper的配置文件,这是最后一步啦。首先还是要强调一下命名规则,这个.xml文件的名字需要和上个定义的接口名相同都是UserMapper(我暂时还没找到名字不同的解决办法,但是在后面的框架整合后可以支持命名不同)。然后在mybatis中,映射文件中的namespace是用于绑定Dao接口的,即面向接口编程。mapper namespace=接口的相对路径。在mapper中可以使用如下标签:
这里我们就看看select,insert,update,delete,resultmap这几个标签。先说前面四个标签,学过数据库的同学很快就能明白是什么意思中,你要执行的什么操作就添加什么标签。然后在标签中添加id属性,id需要填什么呢?id就是你前面定义的接口方法名。这是官方文档中对标签select中所有属性的介绍:
这里我就说一下parameterType,resultType,resultMap属性。parameterType是指定传入参数,但是mybatis可以自动的识别出传入参数的类型,所以要是不清楚传入传输类型,这个属性就不用填写。接下来就是resultType,resultMap,他们长得很像奥,他们也都是指定返回类型。但是看到官方文档中说了他们不能同时存在,但是也不能都没有不然就会在运行时报错。还记得我们要在数据库中和类中转换的第二种的方法吗?你可以指定返回这个你已经定义的resultMap,当然resultMap的功能可远不如此,这里就先不介绍啦。另外只用resultType就是返回任何类型,但是要具体指定。另外着重强调的是如果返回的注意如果是集合情形,那应该是集合可以包含的类型,而不能是集合本身(这个怎么理解啊,就是我们返回的List,我们的resultMap不是List而应该是UserPojo)。
接下来来看看insert,update,delete的标签的属性。
哈哈很多属性我还没用过QAQ,所以就不讲啦。但是这些操作返回的是int的类型,1代表操作成功,0代表操作失败。
在完成标签属性的配置后,我们就可以写sql语句啦,可以看到在传入参数是用的#{}的方式。在接口定义的时候时定义的名字相同时,可以直接使用#{接口中定义传参的属性名}。但是会存在顺序,名字不同等等的情况,这个时候我们需要在接口中加上**@Param(“参数名”)**,表示给参数命名,名称就是括号中的内容。
UserPojo selectById2(@Param(value="id")int id,@Param(value="psw")String psw);
@Param注解的作用是给参数命名,参数命名后就能根据名字得到参数值,正确的将参数传入sql语句中 。
当然细心的你已经发现了set,if,foreach等等的标签,这些被称作动态sql语句,是我觉得mybatis最神奇的地方!比如你准备update数据表,但是你不知道需要更改的是哪个属性,所以你准备把所有需要更新的可能都列举一遍(username+psw或者username或者psw,这只是一个三个属性的表就有三种可能,如果属性更多,你是不是都要哭了)。但是如果我们加入if,set这两个标签,我们只需要写上一句update就可以实现所有的更新。
<update id="updataUser" parameterType="com.hg.pojo.UserPojo" >
update user_test
<set>
<if test="username != null">username=#{
username},</if>
<if test="psw != null">psw=#{
psw}</if>
</set>
where id=#{
id}
</update>
还有我们可以批量的增加数据哟:
<insert id="insertUserpojo" parameterType="com.hg.pojo.UserPojo">
insert into user_test(username,psw) values
<foreach collection="list" item="user" separator=",">
(#{
user.username}, #{
user.psw})
</foreach>
</insert>
mybatis真的为了程序员们操碎了心,每一处的细节都优化到极致。比如我们在set标签中加入每个属性的判断,如果这个传入参数不为空就添加到sql语句中,为空亏不添加到sql语句中。mybatis甚至细致到可以帮你完成sql语句的清理工作:
<if test="username != null">username=#{
username},</if>
<if test="psw != null">psw=#{
psw}</if>
你想想会不会出现,第一句话执行但是第二句不执行的情况,那么现在sql语句是不是就变成了 update user_test username=#{username}, 这样的sql语句执行肯定会报错的,但是mybatis会自动检测到这里多了一个逗号,在后面处理掉这个逗号,返回你想要的结果。虽然不知道是怎么实现的,但是真的不得不感叹mybatis的强大,而且这也仅仅只是动态sql的小小的一部分。如果你想深入了解mybatis,可以参考mybatis的官方文档,我把它放在博客的开始的位置(mybatis的官方文档是被很多人好评的,即使你从未用过mybatis,看了文档后都能模仿出一个mybatis的工程)。
在测试开始前我们要回到我们最初的mybatis-config.xml配置文件中,我们需要让配置文件扫描我们的mapper映射文件,可以参考大神写得四种加载方法https://blog.csdn.net/tanga842428/article/details/79285957
<mappers>
<mapper resource="com/hg/mapper/UserMapper.xml"/>
</mappers>
在测试之前,我还要推荐使用log4j,这样我们能在控制台看到sql语句的生成,使用的方法也很简单。新建一个log4j.properties在里面添加如下内容:
log4j.rootLogger=DEBUG,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.org.apache=INFO
再到mybatis-config.xml配置文件添加如下代码:
<settings>
<setting name="lazyLoadingEnabled" value="false" />
<setting name="logImpl" value="LOG4J" />
</settings>
好啦现在开始我们的测试吧:
简单说下吧:首先我写了一个静态的加载(当然也可以封装到一个类中),每次调用这个类时就会加载这个方法。首先 通过Resources.getResourceAsStream(“mybatis-config.xml”)获取到配置文件的输入流,然后通过SqlSessionFactoryBuilder().build(in)创建SqlSessionFactory ,调用factory.openSession()获取SqlSession ,最后通过session.getMapper获取到我们的UserMapper接口,之后我们就可以调用接口中的方法来执行sql操作啦。注意两点哟:1:SqlSession 在每次用完后必须关闭,2:只要对数据库中的数据有操作的,切记一定要在最后提交session.commit(),否则数据库不会执行更新操作 。控制台不仅不会报错,还会还告诉你执行成功,但是在数据库中不执行任何操作。
public class MyTest { private static SqlSessionFactory factory=null; private static UserMapper dao=null; private static SqlSession session=null; static { InputStream in = null; try { in = Resources.getResourceAsStream("mybatis-config.xml"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } factory = new SqlSessionFactoryBuilder().build(in); session= factory.openSession(); dao= session.getMapper(UserMapper.class); }
public static void main(String[] args) throws IOException { //MyTest.test1();//测试selectAll方法 //MyTest.test2();//测试selectById方法 //MyTest.test3();//测试selectAll1方法 //MyTest.test4();//测试selectAll2方法 //MyTest.test5();//测试updataUser方法 //MyTest.test6();//批量insertUserpojo方法 //MyTest.test7();//测试selectById2方法 session.close(); } public static void test1() { // 通过新建pojo类的属性名与数据库列名相同 List<UserPojo> list = dao.selectAll(); System.out.println("selectAll" + list); } public static void test2() { System.out.println(dao.selectById(1).toString()); } public static void test3() { /*通过新建pojo类的属性名与数据库列名不相同 */ List<UserPojo1> list =dao.selectAll1(); System.out.println("selectAll1()"+list); } public static void test4() { /*2.使用resultMap指定映射*/ List<UserPojo1> list =dao.selectAll2(); System.out.println("selectAll2"+list); } public static void test5() { /* 使用动态sql语句 */ UserPojo pojo=new UserPojo(); pojo.setId(1); pojo.setPsw("更改密码hehe"); int state=dao.updataUser(pojo); System.out.println(state); session.commit(); /*切记一定要在最后提交session.commit(), 否则数据库不会执行更新操作,除了对查询操作, 其余对于数据有改动的都需要 session.commit();*/ } public static void test6() { UserPojo pojo=new UserPojo(); pojo.setUsername("1号人物"); pojo.setPsw("aaaaaaa"); UserPojo pojo1=new UserPojo(); pojo1.setUsername("2号人物"); pojo1.setPsw("bbbbbb"); UserPojo pojo2=new UserPojo(); pojo2.setUsername("3号人物"); pojo2.setPsw("cccccc"); List<UserPojo> list=new ArrayList<>(); list.add(pojo); list.add(pojo1); list.add(pojo2); System.out.println(dao.insertUserpojo(list)); session.commit(); } public static void test7() { UserPojo pojo=dao.selectById2(11, "aaaaaaa"); System.out.println(pojo.toString()); }
}
还记得文章开头说MyBatis 可以使用简单的 XML 或注解吗,那么mybatis的注解怎么使用呢?
@Delete("delete from user_test where id =#{id}")
int deletUser(int id);
对的!只需要在我们的接口中声明方法的时候加上注解,不用再去.xml中配置声明了。但是我个人现在还是觉得动态sql和resultmap比注解易读且方便,或许在未来更新换代的时候能提供更方便的注解模式。
至此本篇博客就到此为止啦,感谢老师和师兄们的热情帮助,让我顺利完成本篇博客!对代码还不清楚或者需要jar包的同学可以到https://github.com/tony-bryant/MyBatisSample下载源码来查看。作为一个才开始学习框架的菜鸟,很多原理以及实现不是很清楚,文中也会有有错误,如果发现错误希望能够帮我指出来,谢谢大家!
最后推荐两位大神的博客分别是MyBatis原理浅析+Mybatis之工作原理,感兴趣的同学可以去学习学习。