myBatis入门学习_上
2018-01-06 21:13
232 查看
MyBatis 百度百科介绍
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAOs)
下载地址
点我去下载地址推荐下载版本 mybatis-3.1.1-bundle.zip
下载完成后,拷贝所有jar包到工程里面
环境搭建
创建一个数据库……….自己创建,导入数据,复制sql,执行一下就行
/* Navicat MySQL Data Transfer Source Server : connection Source Server Version : 50715 Source Host : localhost:3306 Source Database : mybatis Target Server Type : MYSQL Target Server Version : 50715 File Encoding : 65001 Date: 2016-12-01 22:40:43 */ SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for items -- ---------------------------- DROP TABLE IF EXISTS `items`; CREATE TABLE `items` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(32) NOT NULL COMMENT '商品名称', `price` float(10,1) NOT NULL COMMENT '商品定价', `detail` text COMMENT '商品描述', `pic` varchar(64) DEFAULT NULL COMMENT '商品图片', `createtime` datetime NOT NULL COMMENT '生产日期', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of items -- ---------------------------- INSERT INTO `items` VALUES ('1', '台式机', '3000.0', '该电脑质量非常好!!!!', null, '2015-02-03 13:22:53'); INSERT INTO `items` VALUES ('2', '笔记本', '6000.0', '笔记本性能好,质量好!!!!!', null, '2015-02-09 13:22:57'); INSERT INTO `items` VALUES ('3', '背包', '200.0', '名牌背包,容量大质量好!!!!', null, '2015-02-06 13:23:02'); -- ---------------------------- -- Table structure for orderdetail -- ---------------------------- DROP TABLE IF EXISTS `orderdetail`; CREATE TABLE `orderdetail` ( `id` int(11) NOT NULL AUTO_INCREMENT, `orders_id` int(11) NOT NULL COMMENT '订单id', `items_id` int(11) NOT NULL COMMENT '商品id', `items_num` int(11) DEFAULT NULL COMMENT '商品购买数量', PRIMARY KEY (`id`), KEY `FK_orderdetail_1` (`orders_id`), KEY `FK_orderdetail_2` (`items_id`), CONSTRAINT `FK_orderdetail_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT `FK_orderdetail_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of orderdetail -- ---------------------------- INSERT INTO `orderdetail` VALUES ('1', '3', '1', '1'); INSERT INTO `orderdetail` VALUES ('2', '3', '2', '3'); INSERT INTO `orderdetail` VALUES ('3', '4', '3', '4'); INSERT INTO `orderdetail` VALUES ('4', '4', '2', '3'); -- ---------------------------- -- Table structure for orders -- ---------------------------- DROP TABLE IF EXISTS `orders`; CREATE TABLE `orders` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL COMMENT '下单用户id', `number` varchar(32) NOT NULL COMMENT '订单号', `createtime` datetime NOT NULL COMMENT '创建订单时间', `note` varchar(100) DEFAULT NULL COMMENT '备注', PRIMARY KEY (`id`), KEY `FK_orders_1` (`user_id`), CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of orders -- ---------------------------- INSERT INTO `orders` VALUES ('3', '1', '1000010', '2015-02-04 13:22:35', null); INSERT INTO `orders` VALUES ('4', '1', '1000011', '2015-02-03 13:22:41', null); INSERT INTO `orders` VALUES ('5', '10', '1000012', '2015-02-12 16:13:23', null); -- ---------------------------- -- Table structure for user -- ---------------------------- DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(32) NOT NULL COMMENT '用户名称', `birthday` date DEFAULT NULL COMMENT '生日', `sex` char(1) DEFAULT NULL COMMENT '性别', `address` varchar(256) DEFAULT NULL COMMENT '地址', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of user -- ---------------------------- INSERT INTO `user` VALUES ('1', '王五', null, '2', null); INSERT INTO `user` VALUES ('10', '张三', '2014-07-10', '1', '北京市'); INSERT INTO `user` VALUES ('16', '张小明', null, '1', '河南郑州'); INSERT INTO `user` VALUES ('22', '陈小明', null, '1', '河南郑州'); INSERT INTO `user` VALUES ('24', '张三丰', null, '1', '河南郑州'); INSERT INTO `user` VALUES ('25', '陈小明', null, '1', '河南郑州'); INSERT INTO `user` VALUES ('26', '王五', null, null, null);
搭建完数据库环境后,然后开始搭myBatis所需的配置
创建pojo类
package cn.mybatis.pojo; import java.util.Date; /** * * @title User.java * <p>description:用户表映射的PO类</p> * <p>company: www.itheima.com</p> * @author ljh * @version 1.0 */ public class User { private Integer id; private String username;// 用户姓名 private String sex;// 性别 private Date birthday;// 生日 private String address;// 地址 public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "User [id=" + id + ", username=" + username + ", sex=" + sex + ", birthday=" + birthday + ", address=" + address + "]"; } }
在src同级目录下创建config文件夹
创建一个log4j.properties文件….
# Global logging configuration log4j.rootLogger=DEBUG, stdout # Console output... log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layo 1429e ut.ConversionPattern=%5p [%t] - %m%n
创建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> <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?characterEncoding=utf-8"/> <property name="username" value="root"/> <property name="password" value="itcast"/> </dataSource> </environment> </environments> </configuration>
创建sql映射文件,因为mybatis是半自动化sql的框架,所以sql这边还是我们自己写的……所以我们需要创建sql映射文件
在config目录下创建一个sqlmap文件夹,里面创建一个pojo的映射文件….
<?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 :命名空间,用于隔离sql语句,后面会讲另一层非常重要的作用。--> <mapper namespace="test"> <!--parameterType:定义输入到sql中的映射类型,#{id}表示使用preparedstatement设置占位符号并将输入变量id传到sql,其实就相当于jdbc中的 ? --> <!--resultType:定义输出结果映射类型。--> <select id="findUserById" parameterType="int" resultType="cn.mybatis.pojo.User"> select * from user where id = #{id} </select> </mapper>
这里说明一下. 类型如果是八种基本类型的一种,可以直接写,如果不是,需要写类的全路径 比如 java.lang.String,当然,mybatis也提供了一些别名,写别名也是可以的,我个人比较喜欢全路径名,,别名还要记,麻烦,下面是mybatis支持的别名,有兴趣的小伙伴可以看看
这里提一下,mybatis支持自定义别名,后面我会讲,
创建完映射文件后,我们需要在核心配置文件里引入一下映射文件,
<mappers> <mapper resource="sqlmap/User.xml"></mapper> </mappers>
环境已经搭建的差不多了,我们来看看目录结构
现在我们就来使用刚刚写的一条sql语句,做一个查询小案例
package test; import cn.mybatis.pojo.User; 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.io.InputStream; public class Demo { @Test public void fun01() throws IOException { String resources = "mybatisConfig.xml"; //Resources.getResourceAsStream(resources) 这句代码的意思就是查找classpath目录下的mybatisConfig.xml文件 InputStream stream = Resources.getResourceAsStream(resources); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //获取工厂 SqlSessionFactory factory = builder.build(stream); //获取session SqlSession session = factory.openSession(); //test.findUserById 映射文件中的名称空间.查询语句的id 目的是确定使用具体的哪一条sql User user = session.selectOne("test.findUserById", 1); System.out.println(user); session.close(); } }
运行代码如下
嗯,然后我们趁热打铁,写一个插入sql的小案例,
因为我们需要写sql,所以我们需要去映射文件里面添加一条sql语句 ,需要注意的是 #{}里面的值需要跟pojo里面的属性名一致,属性名可以理解为成员变量名
<insert id="insert" parameterType="cn.mybatis.pojo.User"> insert into user(username,birthday,sex,address) VALUE(#{username},#{birthday},#{sex},#{address}); </insert>
然后写测试代码
@Test public void insert() throws IOException { String resources = "mybatisConfig.xml"; //Resources.getResourceAsStream(resources) 这句代码的意思就是查找classpath目录下的mybatisConfig.xml文件 InputStream stream = Resources.getResourceAsStream(resources); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //获取工厂 SqlSessionFactory factory = builder.build(stream); //获取session SqlSession session = factory.openSession(); //test.findUserById 映射文件中的名称空间.查询语句的id 目的是确定使用具体的哪一条sql User user = new User(); user.setUsername("李白"); user.setSex("男"); user.setAddress("广东省"); user.setBirthday(new Date()); session.insert("test.insert", user); session.close(); }
我们来看执行结果
回滚的原因是没有提交事务,我们需要手动提交事务,增删改都需要提交事务,这是需要注意的.
我们添加 session.commit();再进行测试
这里有个小案例,需求是:执行插入语句的同时获取插入时的id,
这里我一开始想的办法是先插入,再查询最大的id,返回,但是这种方案在访问量大的时候就会失效,这是不安全的,由此我们需要使用数据库提供的函数来解决这个问题, LAST_INSERT_ID()
我们来修改映射文件中的sql语句,
<insert id="insert_getId" parameterType="cn.mybatis.pojo.User"> <selectKey keyProperty="id" resultType="int" order="AFTER"> select LAST_INSERT_ID() </selectKey> insert into user(username,birthday,sex,address) VALUE(#{username},#{birthday},#{sex},#{address}); </insert>
keyProperty : 返回的主键存储在pojo中的哪个属性
resultType : 返回数据类型
order:selectKey的执行顺序,是相对与insert语句来说,由于mysql的自增原理执行完insert语句之后才将主键生成,所以这里selectKey的执行顺序为after
测试代码
@Test public void insert() throws IOException { String resources = "mybatisConfig.xml"; //Resources.getResourceAsStream(resources) 这句代码的意思就是查找classpath目录下的mybatisConfig.xml文件 InputStream stream = Resources.getResourceAsStream(resources); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //获取工厂 SqlSessionFactory factory = builder.build(stream); //获取session SqlSession session = factory.openSession(); //test.findUserById 映射文件中的名称空间.查询语句的id 目的是确定使用具体的哪一条sql User user = new User(); user.setUsername("李白"); user.setSex("男"); user.setAddress("广东省"); user.setBirthday(new Date()); System.out.println("执行sql前的user对象user="+user); session.insert("test.insert_getId", user); System.out.println("执行sql后的user对象user="+user); session.commit(); session.close(); }
执行结果如下
我们可以发现,执行完sql后对象的id给赋值了
如果主键id 是uuid生成的,那么又要重写一条sql
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User"> <selectKey resultType="java.lang.String" order="BEFORE" keyProperty="id"> select uuid() </selectKey> insert into user(id,username,birthday,sex,address) values(#{id},#{username},#{birthday},#{sex},#{address}) </insert>
这里使用uuid 的原因是, 执行sql前,id都没生成,所以我们需要提前生成id,
删改我就不演示了,重复造轮子,感觉没必要了.
嗯,我们来抽取一下代码,
SqlSessionFactory factory; InputStream stream; @Before public void createSqlSessionFactory(){ String resources = "mybatisConfig.xml"; //Resources.getResourceAsStream(resources) 这句代码的意思就是查找classpath目录下的mybatisConfig.xml文件 try { stream = Resources.getResourceAsStream(resources); }catch (Exception e){ } SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //获取工厂 factory = builder.build(stream); }
看完这段代码估计就有小朋友有疑问了,@Before 是干啥的?? 其实在方法上增加@Before主键后,哪个方法就会在执行@Test注解方法前执行一遍,嗯,是的没错..相信我,
抽取完这段代码后,我们就可以不用再获取factory了,直接用成员变量就可以了…..
现在又有一个需求,其实就是模糊查询…给一个用户名,模糊查询所有,,,,,
我们先在映射文件里写一条sql语句
<select id="mohuchaxun" resultType="cn.mybatis.pojo.User" parameterType="java.lang.String"> select * from user where username like '%${value}%' </select>
这里需要注意的是 这里不能使用 #{} 了,因为#{} 只是单词的占位符,并不能字符串拼接,, 还需要注意的是 ${}的值只能使用value,
然后写测试代码
@Test public void likeFind() throws IOException { //获取session SqlSession session = factory.openSession(); List<User> users = session.selectList("test.mohuchaxun", "小"); System.out.println("user="+users); session.close(); }
测试运行结果如下
学到这里,我们的myBatis就已经是入门了,,,,,,,,
然后这里做个小结
#{}和${}
#{}其实是占位符的意思,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换.#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。 ${}的意思的拼接符的意思,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。 如果: 输入参数的数据类型是简单的数据类型, #{} 里面的名称随意写 而${} 里面的参数名称必须是value.
parameterType和resultType
parameterType指定输入参数类型,mybatis通过ognl从输入对象中获取参数值拼接在sql中, resultType指定输出参数类型,mybatis 通过sql记录数据映射为resultType指定类型的对象, 如果返回的是集合,只需要指定集合里面的元素的数据类型即可,
selectOne和selectList
其实selectOne的底层就是使用selectList实现的,只不过selectOne做了一些封装,如果使用selectOne查询多条记录则抛出异常: org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3 at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:70) selectList可以查询一条或多条记录。
我们来看看selectOne底层实现原理…….
顺便说一下好了,selectList的底层使用jdbc来做的,有兴趣的小伙伴可以翻翻,
嗯,看到这里应该有些小伙伴已经不耐烦了,那个,,,别打我,因为现在重点才开始
mybatis Mapper动态代理方式
学习代理方式之前,我们需要了解一些规则,因为我们需要根据这种规则才能使用功能,Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
遵循规范如下:
namespace 需要与接口的类路径相同,
Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
Mapper.xml(映射文件)
定义mapper映射文件UserMapper.xml(内容同User.xml),需要修改namespace的值为 UserMapper接口路径。将UserMapper.xml放在classpath 下mapper目录 下。接口定义
Mapper接口方法名和Mapper.xml中定义的statement的id相同Mapper接口方法的输入参数类型和mapper.xml中定义的statement的parameterType的类型相同
-Mapper接口方法的输出参数类型和mapper.xml中定义的statement的resultType的类型相同
创建一个UserMapper文件,拷贝之前的User.xml就行,放在config目录下的mapper目录下,
还需要在核心配置文件里引入一下mapper文件,,
<mappers> <!--<mapper resource="sqlmap/User.xml"></mapper>--> <mapper resource="mapper/UserMapper.xml"></mapper> </mappers>
然后创建一个dao接口,遵守以上规则,,,
package cn.mybatis.dao; import cn.mybatis.pojo.User; import java.util.List; public interface IUserDao { //这里就写一个模糊查询的例子了 public List<User> mohuchaxun(String name); }
写到这里,还需要改userMapper文件,因为规范要求namespace 跟 mapper接口的类路径一致,
<mapper namespace="cn.mybatis.dao.IUserDao"> xxxxxx </mapper>
测试代码如下
@Test public void test_fun02(){ //获取session SqlSession session = factory.openSession(); IUserDao mapper = session.getMapper(IUserDao.class); List<User> user = mapper.mohuchaxun("小"); System.out.println("user="+user); }
运行结果
代码就讲到这里,其实也没什么难度,,只要遵守规则写就好了,,,,
代码就讲的差不多了,接下来就讲讲SqlMapConfig.xml核心配置文件把,,,
配置内容如下
SqlMapConfig.xml中配置的内容和顺序如下:必须按照顺序配置
properties(属性)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)
那个,别担心,我们不是所有都需要会,,只需要会几个重点配置就行了……说实话,我第一次看到有这么多配置的时候都吓了一跳,,,,
需要了解的配置如下
properties(属性)
typeAliases(类型别名)
mappers(映射器)
需要注意的是 必须按照顺序配置 必须按照顺序配置 必须按照顺序配置,
首先我们来试试properties
在resource目录下创建xxx.properties文件jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8 jdbc.username=root jdbc.password=1039191520
然后在核心配置文件里引用一下
<properties resource="datasource.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>
运行测试
typeAliases(类型别名)
之前我们就讲了myBatis支持的一些类型别名,, 这里我就大致的讲一些怎么自定义类型别名把……配置核心配置文件,记住配置顺序,不能放在properties 配置前面,
<properties resource="datasource.properties"></properties> <typeAliases> <!--<typeAlias alias="user" type="cn.mybatis.pojo.User"/> <!–单个别名定义–>--> <package name="cn.mybatis.pojo" /> <!--多个别名定义,扫描整个包下的类,别名为类名(大小写不敏感)--> </typeAliases>
然后我们修改代码,使用别名,就改模糊查询的例子了,因为突出大小写不敏感,所以嘿嘿嘿,你懂的
<select id="mohuchaxun" resultType="uSeR" parameterType="java.lang.String"> select * from user where username like '%${value}%' </select>
代码测试
最后来讲讲mappers(映射器)
相信大家已经有所感悟了把,我们写mapper一直都是一个个的引入的,这样要是在开发中可是很头疼的一件事,mybatis提供了解决方案此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
<mappers> <!--<mapper resource="sqlmap/User.xml"></mapper>--> <!--<mapper resource="mapper/UserMapper.xml"></mapper>--> <package name="cn.mybatis.dao"></package> </mappers>
我们需要重新修改一下目录结构
然后运行测试
myBatis入门就讲到这里,下次讲myBatis拼接sql等等…..撤退啦
相关文章推荐
- Mybatis学习(一) - 快速入门
- MyBatis第一讲学习笔记,mybatis入门基础操作
- mybatis入门学习
- Mybatis入门学习四:Spring 与 MyBatis整合
- MyBatis学习之入门 (一)
- Mybatis 入门学习,简单例子
- MyBatis学习总结(一)——MyBatis快速入门
- mybatis入门学习,mybatis环境搭建
- MyBatis入门学习By项目一
- MyBatis入门学习(一)
- mybatis学习之入门实例
- Spring+SpringMVC+MyBatis深入学习及搭建(十三)——SpringMVC入门程序(二)
- Mybatis(学习一)--基础入门
- 【Mybatis3学习入门】【一】从JDBC到Mybatis
- MyBatis入门学习(Spring整合MyBatis)
- MyBatis入门学习
- MyBatis入门学习(一)
- Mybatis学习笔记(一)-Mybatis入门篇
- mybatis学习笔记,简介及快速入门
- 框架学习系列 mybatis 第七篇 mybatis入门程序之插入数据库后返回主键