MyBatis for Scala 1.0-beta1 Released

MyBatis is a mature and stable persistence framework for java. It is very different from JPA, Hibernate, JDO and other ORM Frameworks. With MyBatis you actually write your SQL as you like, you can use 100% of your database functionality like stored procedures, views, any sql query and any propietary feature supported by your RDBMS. As you already know, SQL is a functional language, so it is declarative and verb centric, the most natural way to interface it with programming languages is to map verbs to functions, not tables to objects. Tables are an implementation detail of how the data is organized in the RDBMS and it is not relevant to the business logic of your application. Most ORMs are model centric, they try to define a static model of your data, mapping relational models to object oriented models and then tries to provide a limited query language over the OO Model. The main problem is that database models change all the time, they are not static at all and when you are coding a specific business logic you rarely have to use the complete model, you usually need a small context with a limited view of your database info.

So, what about MyBatis?

Well, MyBatis Framework doesn’t try to abstract your entire model, it doesn’t try to provide a new limited OO query language neither. It provides a mechanism to map your SQL queries to Functions in your code. So your persistent relational model resides in your database and your application OO model resides in your application code, period. Any interaction within your code and your model are done via a function defined as f : P -> R where P is a parameter type and R a result type, some java examples are:


  // findPerson : Int -> Person
  Person findById(Int id);

  // findPeople : String -> List<Person>
  List<Person> findPeople(String name);

  // findPeople : MyFilter -> List<Person>
  List<Person> findPeople(MyFilter filter);

  // insertPerson : Person -> int
  int insertPerson(Person p);

I know you can argue about the fact that function (insertPerson : Person -> int) has side effects. Yes it has side effects in your database, it is not strictly a function like in mathematics or purist functional languages, but it is not a problem here, it is a function like any other java function that has side effects in some context.

Ok, coming back to MyBatis, it provides only two important things: A way to map your java methods to pure SQL queries, and a way to map the SQL results to any java structure.

You can find more information about MyBatis For Java in the project home page at: http://www.mybatis.org/

Welcome Scala

Scala is not a new language but it is like the new kid on the block. A lot of people are talking about Scala and many java programmers are meeting with it; some people are fascinated and some are disappointed. I am in the fans group.

The problem with Scala is that there are not enough frameworks out there like in java, which has too many. One of the key aspects where we are missing alternative frameworks is for persistence. Yes I know you can use any java framework in Scala, but you will be bump into some idiom clashes. Scala has a concise and pleasant syntax and type system, but when you are using a Java centric API you lose most of them and your code looks like “JaLa” or “ScaVa”.

Finally, Scala and MyBatis ?

Well, after a BIG intro and context, we can go to the topic: Scala and MyBatis meet in heaven; they are mostly functional oriented, so we can talk about mapping functions to queries very naturally.

First of all, I assume you are not a Scala master, but you are a Scala developer.

I will try to explain this with some words first, then i will elaborate over sample code, Let’s start it.

Suppose you have your database defined. So you have your tables, views, stored procedures, data, etc… Now you need to develop some application to manipulate that database and you use your preferred frameworks for MVC or whatever, and you will develop your DAO with MyBatis For Scala.

Illustrate it with a very simple database:

CREATE TABLE person(
  id_ int not null auto_increment,
  name_ varchar(255) not null,
  address_ varchar(255),
  phone_ varchar(20),
  notes_ text,
  primary key (id_)
)

A Table of people, with some fields.
Notice: The underscore at the end of the field names is a pure personal convention.

Now you want to pupulate a view with a list of people, but only need the fields ‘name_’ and ‘phone_’, and the list is filtered by name. The MyBatis-Scala code may look like this:


// Define a type with your model projection [Optional because you can use a Map]
class Person {
  var id : Int = _
  var name : String = _
}

// Define a function findPeople : String -> List[Person] in your DAO layer.
val findPeople = new SelectListBy[String,Person] {
  def xsql = 
    <xsql>
      SELECT
        id_ as id,
        name_ as name,
      FROM
        person
      WHERE
        name_ LIKE #{{name}}
    </xsql>
}

// Then use it anywhere in your code
db.readOnly { 
  implicit session =>

  val list = findPeople("john%")

  for (p <- list)
    println( p.name + ", " + p.phone )

}


Of course you can do a lot of more things like fetch associations (ManyToOne), collections (OneToMany ManyToMany), call stored procedures, build dynamic SQL queries without String concatenation, cache the results, and many many more things. But this post has run too large. So I will publish a second part soon.

But you don’t have to wait for it, there are many more examples and documentation in the main project site at http://mybatis.org/scala/

There are examples for Selects, Inserts, Updates and Deletes, simple a complex mappings to object graphs, etc…

3 Comments

  1. baiping says:

    Hi,Frank,I’m beginning to learn Scala-mybatis, how to use the cache,Please show me,Thank you very much.

    • Frank D. Martínez M. says:

      Hi Baiping,

      I suppose your are using the beta2, so you can call cache(…) in your configuration object (default namespace)

          config.cache()
      

      Or in your configuration space

        config.addSpace("mynamespace") { space =>
          space.cache()
          ...
        }
      

      Read more information about mybatis cache: http://www.mybatis.org/core/sqlmap-xml.html#cache Same options are supported by cache(…) method but it is typesafe.

  2. baiping says:

    Hi Frank, thank you very much.