mybatis简单入门

来源:互联网 发布:淘宝搜索词分析收费 编辑:程序博客网 时间:2024/06/05 16:02

之前我们学习了hibernate,今天我们来学习下mybatis。网上对于这两个orm框架的争论可以说很激烈,这里我们不做瑜亮之争,只是单纯的学习mybatis。

mybatis的有点:1.学习简单;2.mybatis需要手写sql(半自动化),所以调优会很简单。3.作为一个orm框架,使用方便是肯定的了。

下面我们来进行简单的学习使用mybatis。

一:初识mybatis

首先我们创建一个maven工程test_mybatis。

pom.xml

<dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.1</version></dependency><!-- mysql连接 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.34</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency></dependencies>
package com.julyday.test_mybatis.entity;public class User {private int id;private String name;private int age;public User() {}public User(String name, int age) {this.name = name;this.age = age;}//getter setter@Overridepublic String toString() {return "User [id=" + id + ", name=" + name + ", age=" + age + "]";}}

mybatis的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"><mapper namespace="User"><resultMap type="com.julyday.test_mybatis.entity.User" id="UserResult"><id column="id" jdbcType="INTEGER" property="id" /><result column="name" jdbcType="VARCHAR" property="name" /><result column="age" jdbcType="INTEGER" property="age" /></resultMap><sql id="col">id,name,age</sql><insert id="insert" useGeneratedKeys="true" >insert into user(name,age) values (#{name,jdbcType=VARCHAR},#{age,jdbcType=INTEGER})</insert><select id="find" resultMap="UserResult">SELECT <include refid="col"/> FROM user WHERE id = #{id,jdbcType=INTEGER}</select><select id="selectOrder" resultMap="UserResult">SELECT <include refid="col"/> FROM user order by ${_parameter}</select><select id="getList" parameterType="com.julyday.test_mybatis.entity.User" resultMap="UserResult">SELECT <include refid="col"/> FROM user<where><if test="name != null and !"".equals(name.trim())">  name = #{name,jdbcType=VARCHAR}  </if>  <if test="age > 0">  and age = #{age,jdbcType=INTEGER}  </if></where></select><select id="sqlInject" parameterType="User" resultMap="UserResult">SELECT <include refid="col"/> FROM user<where><if test="name != null and !"".equals(name.trim())">  name = ${name}  </if>  <if test="age > 0">  and age = #{age,jdbcType=INTEGER}  </if></where></select><update id="update">update user <set><if test="name != null and !"".equals(name.trim())">  name = #{name,jdbcType=VARCHAR},  </if>  <if test="age > 0">  age = #{age,jdbcType=INTEGER}  </if></set>where id = #{id,jdbcType=INTEGER}</update><delete id="delete">delete from user where id = #{id,jdbcType=INTEGER}</delete></mapper>


resultMap:返回结果,type对应我们的实体,id别名。

id:表示主键

column:数据库对应字段

jdbcType:表示对应的jdbc类型,写jdbc的同学可能比较熟悉(java.sql.Types),对象的数据库类型有个对应关系,这里不多说了。

property:实体中的属性字段

sql:不是我们通常意义上的sql,他是为了简便字段使用的,当字段个数较多是很有用,同时也不会有n+1的情况出现。

insert,select,update,delete:对应的数据库操作。select中<include refid="col"/>,就是用到我们之前的sql了。

where:对应了数据库中的关键字,在这里,如果里面没有查询条件就不含where关键字,同样如果第一个含有and或者or他会去除,我们这如果name没值,age前的and会去除。

set:同where。

${}和#{}的区别:select * from user where name = ${name},当参数为字符串类型时,${name}是“julyday”,结果是select * from user where name = julyday,而#{name}的结果是select * from user where name = 'julyday',这个就像我们在jdbc中直接字符串+ 和 setString()的对比一样,前者会出现sql注入的风险,name的传值是“'' or 1=1”,这样前一个就查了全表,后一个查询结果是0条。当然在order by的后面我们是需要用#{},不然排序是不起作用的。

这里为方便我们排查错误我们可以查看日志,但是mybatis没有像hibernate一样提供自己的日志服务,我们需要第三方的log4j来打印日志。

log4j.rootLogger=debug,stdout,logfile### 把日志信息输出到控制台 ###log4j.appender.stdout=org.apache.log4j.ConsoleAppender#log4j.appender.stdout.Target=System.errlog4j.appender.stdout.layout=org.apache.log4j.SimpleLayout### 把日志信息输出到文件:jbit.log ###log4j.appender.logfile=org.apache.log4j.FileAppenderlog4j.appender.logfile.File=D:/test.loglog4j.appender.logfile.layout=org.apache.log4j.PatternLayoutlog4j.appender.logfile.layout.ConversionPattern=[test_mybatis][%p] %d{yyyy-MM-dd HH:mm:ss} %F %m%n ###显示SQL语句部分log4j.logger.com.ibatis=DEBUGlog4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUGlog4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUGlog4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUGlog4j.logger.java.sql.Connection=DEBUGlog4j.logger.java.sql.Statement=DEBUGlog4j.logger.java.sql.PreparedStatement=DEBUG
log4j的配置这里就不再赘述了。

当然mapper这个文件可以在源码的找到,不会写的朋友可以自己下载源码看下,~\src\test\java\org\apache\ibatis\submitted\complex_property下,包括下面的Configuration.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><!--   <settings>    <setting name="useGeneratedKeys" value="false"/>    <setting name="useColumnLabel" value="true"/>  </settings> -->  <typeAliases>    <typeAlias alias="User" type="com.julyday.test_mybatis.entity.User"/>  </typeAliases>  <environments default="development">    <environment id="development">      <transactionManager type="JDBC">        <property name="" value=""/>      </transactionManager>      <dataSource type="UNPOOLED">        <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="mybatis/User.xml"/>  </mappers></configuration>
typeAliases:给我们的实体启一个别名

environments:数据库的配置信息

mappers:对应的mapper文件

下面是我们的测试文件:

package com.julyday.test_mybatis;import java.io.IOException;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.After;import org.junit.Before;import org.junit.Test;import com.julyday.test_mybatis.entity.User;public class TestMybatis {private SqlSession sqlSession;@Beforepublic void init() {Reader reader;try {reader = Resources.getResourceAsReader("Configuration.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);sqlSession = sqlSessionFactory.openSession();} catch (IOException e) {e.printStackTrace();}}@Testpublic void testInsert() {User u = new User("julyday", 18);sqlSession.insert("User.insert", u);sqlSession.commit();}@Testpublic void testFind() {User u = sqlSession.selectOne("User.find", 1);System.out.println(u);}@Testpublic void testGetList() {User user = new User();//user.setAge(18);//user.setName("julyday");user.setName("'' or 1=1 ");//List<User> list = sqlSession.selectList("User.getList", user);List<User> list = sqlSession.selectList("User.sqlInject", user);System.out.println(list.size());for(User u : list){System.out.println(u);}}@Testpublic void testSelectOrder() {List<User> list = sqlSession.selectList("User.selectOrder", "age desc");System.out.println(list.size());for(User u : list){System.out.println(u);}}@Testpublic void testUpdate() {User u = sqlSession.selectOne("User.find", 1);u.setAge(12);sqlSession.update("User.update", u);sqlSession.commit();}@Testpublic void testDelete() {sqlSession.delete("User.delete",1);}@Afterpublic void destory() {sqlSession.close();}}

二:面向接口编程

package com.julyday.test_mybatis.dao;import java.util.List;import com.julyday.test_mybatis.entity.User;public interface UserDao {public void insert(User user);public User find(int id);public List<User> selectOrder(String order);public List<User> getList(User user);public List<User> sqlInject(User user);public void update(User user);public void delete(int id);}
copy一下User.xml成UserDao.xml
修改<mapper namespace="com.julyday.test_mybatis.dao.UserDao">,这个命名空间必须唯一,这是反射的基础。这里就简单的看下源码就知道了,同时也会加深你对mybatis的理解。可以从ud = sqlSession.getMapper(UserDao.class);这个开始,在DefaultSqlSession类里面,当然你必须对代理和反射有一定的了解,这里简单的说下可以看MapperProxy.cachedMapperMethod()方法。
private MapperMethod cachedMapperMethod(Method method) {    MapperMethod mapperMethod = methodCache.get(method);    if (mapperMethod == null) {      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());      methodCache.put(method, mapperMethod);    }    return mapperMethod;  }
反射的invoke方法最后一句return mapperMethod.execute(sqlSession, args);就是正文了,MapperMethod这个类就是他的庐山真面目了,后面根据我们的sql类型找到对应的分支看下。这个就不继续下去了。
我们的测试类:
package com.julyday.test_mybatis;import java.io.IOException;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.After;import org.junit.Before;import org.junit.Test;import com.julyday.test_mybatis.dao.UserDao;import com.julyday.test_mybatis.entity.User;public class TestDao {private SqlSession sqlSession;private UserDao ud ;@Beforepublic void init() {Reader reader;try {reader = Resources.getResourceAsReader("Configuration.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);sqlSession = sqlSessionFactory.openSession();ud = sqlSession.getMapper(UserDao.class);} catch (IOException e) {e.printStackTrace();}}@Testpublic void testInsert() {User u = new User("zhangsan", 28);ud.insert(u);sqlSession.commit();}@Testpublic void testFind() {User u = ud.find(1);System.out.println(u);}@Testpublic void testGetList() {User user = new User();//user.setAge(18);//user.setName("julyday");user.setName("'' or 1=1 ");//List<User> list =ud.getList(user);List<User> list = ud.sqlInject(user);System.out.println(list.size());for(User u : list){System.out.println(u);}}@Testpublic void testSelectOrder() {List<User> list = ud.selectOrder("age desc");System.out.println(list.size());for(User u : list){System.out.println(u);}}@Testpublic void testUpdate() {User u = ud.find(1);u.setAge(19);ud.update(u);sqlSession.commit();}@Testpublic void testDelete() {ud.delete(3);sqlSession.commit();}@Afterpublic void destory() {sqlSession.close();}}

三:mybatis自动化工具类generator

首先是jar包的下载:mybatis-generator-core-1.3.2.jar。jar下载
这里我放在D:\generator,写一个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><!-- 数据库驱动包位置 --><classPathEntry location="D:\generator\mysql-connector-java-5.1.34.jar" /> <!-- <classPathEntry location="C:\oracle\product\10.2.0\db_1\jdbc\lib\ojdbc14.jar" />--><context id="DB2Tables" targetRuntime="MyBatis3"><!-- 是否去除自动生成的注释 true:是 : false:否 --><commentGenerator><property name="suppressAllComments" value="true" /></commentGenerator><!-- 数据库链接URL、用户名、密码 --> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/mybatis" userId="root" password="root"> <!--<jdbcConnection driverClass="oracle.jdbc.driver.OracleDriver" connectionURL="jdbc:oracle:thin:@localhost:1521:orcl" userId="msa" password="msa">--></jdbcConnection><javaTypeResolver><property name="forceBigDecimals" value="false" /></javaTypeResolver><!-- 生成模型的包名和位置 --><javaModelGenerator targetPackage="com.julyday.test_mybatis.entity" targetProject="D:\generator\src"><property name="enableSubPackages" value="true" /><property name="trimStrings" value="true" /></javaModelGenerator><!-- 生成的映射文件包名和位置 --><sqlMapGenerator targetPackage="mybatis" targetProject="D:\generator\src"><property name="enableSubPackages" value="true" /></sqlMapGenerator><!-- 生成DAO的包名和位置 --><javaClientGenerator type="XMLMAPPER" targetPackage="com.julyday.test_mybatis.dao" targetProject="D:\generator\src"><property name="enableSubPackages" value="true" /></javaClientGenerator><!-- 要生成那些表(更改tableName和domainObjectName就可以) --> <table tableName="user" domainObjectName="User" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false" /></context></generatorConfiguration>
然后就是执行了,java -jar mybatis-generator-core-1.3.2.jar -configfilegenerator.xml -overwrite  这里targetProject目录是必须要存在的,可以写成你eclipse项目的路径。
这里我们就简单的说下最后一个table,很明显是数据库的表到类的映射,第一个是表名,第二个是类名,后面的根据英文大家都能猜到是干啥的,不明白的大家可以自己尝试下。多个表的话就写对个table。

四:表关联关系

一对多:
实体类不看了,有需要的朋友下代码看。
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"><mapper namespace="Student"><resultMap type="com.julyday.test_mybatis.entity.Student" id="StudentResult"><id column="id" jdbcType="INTEGER" property="id" /><result column="name" jdbcType="VARCHAR" property="name" /><result column="age" jdbcType="INTEGER" property="age" /><result column="gid" jdbcType="INTEGER" property="gid" /></resultMap><select id="find" resultMap="StudentResult">SELECT id,name,age,gid FROM student WHERE id = #{id,jdbcType=INTEGER}</select></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"><mapper namespace="Grade"><resultMap type="com.julyday.test_mybatis.entity.Grade" id="GradeResult"><id column="g_id" jdbcType="INTEGER" property="id" /><result column="gname" jdbcType="VARCHAR" property="gname" /><result column="gdesc" jdbcType="VARCHAR" property="gdesc" /> <collection property="students" resultMap="Student.StudentResult" /><!-- <collection property="students" ofType="com.julyday.test_mybatis.entity.Student" column="gid"><id column="id" jdbcType="INTEGER" property="id" /><result column="name" jdbcType="VARCHAR" property="name" /><result column="age" jdbcType="INTEGER" property="age" /><result column="gid" jdbcType="INTEGER" property="gid" /></collection>--></resultMap><select id="find" resultMap="GradeResult">SELECT id as g_id,gname,gdesc FROM grade WHERE id = #{id,jdbcType=INTEGER}</select><select id="findAll" parameterType="com.julyday.test_mybatis.entity.Grade" resultMap="GradeResult">    SELECT g.id as g_id,g.gname,g.gdesc,s.id,s.name,s.age,s.gid    FROM Grade g left join student s on g.id = s.gid where g.id=#{id,jdbcType=INTEGER} </select></mapper>
一对多,一的一方用collection,两种collection任选一个。
@Testpublic void testFindall() {Grade grade = new Grade();grade.setId(1);List<Grade> list = sqlSession.selectList("Grade.findAll",grade);for(Grade g : list){System.out.println(g.toString());List<Student> ls = g.getStudents();for(Student s : ls){System.out.println(s.toString());}}}
测试没问题。

多对一:
<?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="Order"><resultMap type="com.julyday.test_mybatis.entity.Order" id="OrderResult"><id column="id" jdbcType="INTEGER" property="id" /><result column="name" jdbcType="VARCHAR" property="name" /></resultMap><select id="find" resultMap="OrderResult">SELECT id,name FROM orders WHERE id = #{id,jdbcType=INTEGER}</select></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"><mapper namespace="Product"><resultMap type="com.julyday.test_mybatis.entity.Product" id="ProductResult"><id column="p_id" jdbcType="INTEGER" property="id"/><result column="p_name" jdbcType="VARCHAR" property="name"/><result column="price" jdbcType="INTEGER" property="price"/><result column="oid" jdbcType="INTEGER" property="oid"/> <association property="order" javaType="com.julyday.test_mybatis.entity.Order"><id column="id" jdbcType="INTEGER" property="id" /><result column="name" jdbcType="VARCHAR" property="name" /></association><!-- <association property="order" resultMap="Order.OrderResult"/>--></resultMap><select id="find" resultMap="ProductResult">SELECT id as p_id,name as p_name,price,oid FROM product WHERE id = #{id,jdbcType=INTEGER}</select><select id="findAll" resultMap="ProductResult">SELECT p.id as p_id,p.name as p_name,p.price,p.oid,o.id,o.name FROM product p right join orders o on p.oid = o.id WHERE p.id = #{id,jdbcType=INTEGER}</select></mapper>
多对一,用association,同样的两个association选一个。
@Testpublic void testFindall() {Product product = new Product();product.setId(3);List<Product> list = sqlSession.selectList("Product.findAll",product);for(Product p : list){System.out.println(p.toString());Order o  = p.getOrder();System.out.println(o.toString());}}
测试OK.

最后国际惯例,贴上全部代码的git地址:代码下载地址








0 0