mybatis简单入门

之前我们学习了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

	@Override
	public 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.err
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
### 把日志信息输出到文件:jbit.log ###
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=D:/test.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=[test_mybatis][%p] %d{yyyy-MM-dd HH:mm:ss} %F %m%n
 
###显示SQL语句部分
log4j.logger.com.ibatis=DEBUG
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.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;

	@Before
	public void init() {
		Reader reader;
		try {
			reader = Resources.getResourceAsReader("Configuration.xml");
			SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
					.build(reader);
			sqlSession = sqlSessionFactory.openSession();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Test
	public void testInsert() {
		User u = new User("julyday", 18);
		sqlSession.insert("User.insert", u);
		sqlSession.commit();
	}
	
	@Test
	public void testFind() {
		User u = sqlSession.selectOne("User.find", 1);
		System.out.println(u);
	}
	
	@Test
	public 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);
		}
	}
	
	@Test
	public void testSelectOrder() {
		List<User> list = sqlSession.selectList("User.selectOrder", "age desc");
		System.out.println(list.size());
		for(User u : list){
			System.out.println(u);
		}
	}
	
	
	
	@Test
	public void testUpdate() {
		User u = sqlSession.selectOne("User.find", 1);
		u.setAge(12);
		sqlSession.update("User.update", u);
		sqlSession.commit();
	}
	
	@Test
	public void testDelete() {
		sqlSession.delete("User.delete",1);
	}

	@After
	public 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 ;
	@Before
	public 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();
		}
	}

	@Test
	public void testInsert() {
		User u = new User("zhangsan", 28);
		ud.insert(u);
		sqlSession.commit();
	}
	
	@Test
	public void testFind() {
		User u = ud.find(1);
		System.out.println(u);
	}
	
	@Test
	public 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);
		}
	}
	
	@Test
	public void testSelectOrder() {
		List<User> list = ud.selectOrder("age desc");
		System.out.println(list.size());
		for(User u : list){
			System.out.println(u);
		}
	}
	
	@Test
	public void testUpdate() {
		User u = ud.find(1);
		u.setAge(19);
		ud.update(u);
		sqlSession.commit();
	}
	
	@Test
	public void testDelete() {
		ud.delete(3);
		sqlSession.commit();
	}

	@After
	public 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 -configfile generator.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任选一个。
@Test
	public 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选一个。
@Test
	public 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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值